update detech new message and auto sync conversations
This commit is contained in:
parent
b6d6a6dd79
commit
9dfa87e2c0
|
|
@ -1,3 +0,0 @@
|
||||||
VITE_API_URL=https://notable-recently-seagull.ngrok-free.app/api/v1/
|
|
||||||
VITE_WS_URL=wss://notable-recently-seagull.ngrok-free.app
|
|
||||||
VITE_API_TYPE_URL=MyCoolApp
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -12,7 +12,9 @@ port.onMessage.addListener((msg: IMsg<any>) => {
|
||||||
// Set height input chat tager cho nó ra dễ click
|
// Set height input chat tager cho nó ra dễ click
|
||||||
contentService.fixedHeightChatInput();
|
contentService.fixedHeightChatInput();
|
||||||
|
|
||||||
if (msg.type !== "socket") return;
|
if (msg.type !== "socket") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (msg.event) {
|
switch (msg.event) {
|
||||||
case EVENTS.GET_CONVERSATIONS: {
|
case EVENTS.GET_CONVERSATIONS: {
|
||||||
|
|
@ -36,3 +38,9 @@ port.onMessage.addListener((msg: IMsg<any>) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// DETECH NEW MESSAGE (INTERVAl)
|
||||||
|
contentService.detectNewMessage();
|
||||||
|
|
||||||
|
// SYNC CONVERSASIONS (INTERVAL)
|
||||||
|
contentService.startSyncConversations();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1 @@
|
||||||
import { clsx, type ClassValue } from "clsx"
|
|
||||||
import { twMerge } from "tailwind-merge"
|
|
||||||
|
|
||||||
export function cn(...inputs: ClassValue[]) {
|
|
||||||
return twMerge(clsx(inputs))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { TeamsChatService } from "./teams-chat.service";
|
||||||
import { EVENTS } from "@/lib/event";
|
import { EVENTS } from "@/lib/event";
|
||||||
import { typeingService } from "./typing.service";
|
import { typeingService } from "./typing.service";
|
||||||
import { delay } from "@/features/app";
|
import { delay } from "@/features/app";
|
||||||
|
import { messageApi } from "@/api/message-api.service";
|
||||||
|
|
||||||
export class ContentService {
|
export class ContentService {
|
||||||
service: TeamsChatService;
|
service: TeamsChatService;
|
||||||
|
|
@ -283,7 +284,7 @@ export class ContentService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getConversations(_: IMsg<any>) {
|
async getConversations(_?: IMsg<any>) {
|
||||||
queue.add(async () => {
|
queue.add(async () => {
|
||||||
console.log("[Queue] Handling GET_CONVERSATIONS");
|
console.log("[Queue] Handling GET_CONVERSATIONS");
|
||||||
|
|
||||||
|
|
@ -381,7 +382,7 @@ export class ContentService {
|
||||||
await this._waitToloadMessages();
|
await this._waitToloadMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._clickIfExists(this.service.elTags.close_reply_btn);
|
await this._clickIfExists(this.service.elTags.close_reply_btn);
|
||||||
|
|
||||||
await this._rightClickMessage(time);
|
await this._rightClickMessage(time);
|
||||||
|
|
||||||
|
|
@ -443,4 +444,53 @@ export class ContentService {
|
||||||
|
|
||||||
tryFind();
|
tryFind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async detectNewMessage(interval = 2000) {
|
||||||
|
console.log("[Monitor] Starting...");
|
||||||
|
// this.initialHistories = this.extractAllMessages();
|
||||||
|
// this.lastMessage = this.initialHistories.pop();
|
||||||
|
|
||||||
|
// await messageApi.sendBulkMessages(this.initialHistories);
|
||||||
|
setInterval(async () => {
|
||||||
|
const aria_value = document
|
||||||
|
.querySelector(
|
||||||
|
'[aria-labelledby^="cn-normal-notification-main-content-"]'
|
||||||
|
)
|
||||||
|
?.getAttribute("aria-labelledby");
|
||||||
|
|
||||||
|
if (!aria_value) {
|
||||||
|
console.log("No new message...");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const room_id = aria_value
|
||||||
|
.split(" ")[0]
|
||||||
|
.replaceAll("cn-normal-notification-main-content-", "");
|
||||||
|
|
||||||
|
if (!room_id) return;
|
||||||
|
|
||||||
|
console.log({ room_id, aria_value });
|
||||||
|
|
||||||
|
queue.add(async () => {
|
||||||
|
console.log("[Queue] Handling SYNC NEW MESSAGE");
|
||||||
|
|
||||||
|
this._clickToConversation(room_id);
|
||||||
|
|
||||||
|
await delay(2000);
|
||||||
|
|
||||||
|
const allMessages = this.service.extractAllMessages();
|
||||||
|
|
||||||
|
const lastMessage = allMessages.at(-1);
|
||||||
|
|
||||||
|
if (!lastMessage) return;
|
||||||
|
|
||||||
|
await messageApi.sendSingleMessage(lastMessage);
|
||||||
|
});
|
||||||
|
}, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
startSyncConversations() {
|
||||||
|
setInterval(() => this.getConversations(), 20000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,14 @@ export class TeamsChatService {
|
||||||
"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div",
|
"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div",
|
||||||
conatainer_conversations:
|
conatainer_conversations:
|
||||||
"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div/div[1]",
|
"/html/body/div[1]/div/div/div/div[5]/div[1]/div[1]/div[2]/div[1]/div[1]/div/div[1]",
|
||||||
container_chat:
|
container_chat: '[data-testid="message-wrapper"]',
|
||||||
// "/html/body/div[1]/div/div/div/div[6]/div[4]/div/div[1]/div/div[1]/div/div/div/div[1]/div/div/div[4]",
|
|
||||||
'[data-testid="message-wrapper"]',
|
|
||||||
|
|
||||||
root_id: '[aria-selected="true"] [id^="chat-list-item"]',
|
root_id: '[aria-selected="true"] [id^="chat-list-item"]',
|
||||||
room_name: '[data-tid="chat-title"]',
|
room_name: '[data-tid="chat-title"]',
|
||||||
close_reply_btn:
|
close_reply_btn:
|
||||||
'[data-track-action-scenario="messageQuotedReplyDismissed"]',
|
'[data-track-action-scenario="messageQuotedReplyDismissed"]',
|
||||||
reply_btn: '[aria-label="Reply"]',
|
reply_btn: '[aria-label="Reply"]',
|
||||||
chat_input:
|
chat_input: '[placeholder="Type a message"]',
|
||||||
// "/html/body/div[1]/div/div/div/div[6]/div[4]/div/div[1]/div/div[3]/div/div[3]/div/div[2]/div/div[2]/div[1]/div",
|
|
||||||
'[placeholder="Type a message"]',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public getCurrentRoomInfo(): { room_id?: string; room_name?: string } {
|
public getCurrentRoomInfo(): { room_id?: string; room_name?: string } {
|
||||||
|
|
@ -160,7 +156,7 @@ export class TeamsChatService {
|
||||||
this.initialHistories = this.extractAllMessages();
|
this.initialHistories = this.extractAllMessages();
|
||||||
this.lastMessage = this.initialHistories.pop();
|
this.lastMessage = this.initialHistories.pop();
|
||||||
|
|
||||||
await messageApi.sendBulkMessages(this.initialHistories);
|
// await messageApi.sendBulkMessages(this.initialHistories);
|
||||||
setInterval(async () => await this.detectNewMessages(), interval);
|
setInterval(async () => await this.detectNewMessages(), interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^9.9.0",
|
"@faker-js/faker": "^9.9.0",
|
||||||
"@keyv/redis": "^5.0.0",
|
"@keyv/redis": "^5.0.0",
|
||||||
|
"@nestjs/axios": "^4.0.1",
|
||||||
"@nestjs/cache-manager": "^3.0.1",
|
"@nestjs/cache-manager": "^3.0.1",
|
||||||
"@nestjs/class-transformer": "^0.4.0",
|
"@nestjs/class-transformer": "^0.4.0",
|
||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
|
|
@ -2428,6 +2429,17 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nestjs/axios": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-68pFJgu+/AZbWkGu65Z3r55bTsCPlgyKaV4BSG8yUAD72q1PPuyVRgUwFv6BxdnibTUHlyxm06FmYWNC+bjN7A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||||
|
"axios": "^1.3.1",
|
||||||
|
"rxjs": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nestjs/cache-manager": {
|
"node_modules/@nestjs/cache-manager": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nestjs/cache-manager/-/cache-manager-3.0.1.tgz",
|
||||||
|
|
@ -4862,7 +4874,6 @@
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/atomic-sleep": {
|
"node_modules/atomic-sleep": {
|
||||||
|
|
@ -4911,6 +4922,18 @@
|
||||||
"node": ">= 6.0.0"
|
"node": ">= 6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/axios": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
|
||||||
|
"integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.6",
|
||||||
|
"form-data": "^4.0.4",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/b4a": {
|
"node_modules/b4a": {
|
||||||
"version": "1.6.7",
|
"version": "1.6.7",
|
||||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz",
|
||||||
|
|
@ -5725,7 +5748,6 @@
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
|
|
@ -6094,7 +6116,6 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
|
|
@ -6420,7 +6441,6 @@
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"es-errors": "^1.3.0",
|
"es-errors": "^1.3.0",
|
||||||
|
|
@ -7257,6 +7277,27 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.15.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||||
|
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"debug": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.5",
|
"version": "0.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||||
|
|
@ -7321,7 +7362,6 @@
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
|
|
@ -7348,7 +7388,6 @@
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
|
|
@ -7358,7 +7397,6 @@
|
||||||
"version": "2.1.35",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "1.52.0"
|
"mime-db": "1.52.0"
|
||||||
|
|
@ -10625,6 +10663,13 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/proxy-from-env": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@faker-js/faker": "^9.9.0",
|
"@faker-js/faker": "^9.9.0",
|
||||||
"@keyv/redis": "^5.0.0",
|
"@keyv/redis": "^5.0.0",
|
||||||
|
"@nestjs/axios": "^4.0.1",
|
||||||
"@nestjs/cache-manager": "^3.0.1",
|
"@nestjs/cache-manager": "^3.0.1",
|
||||||
"@nestjs/class-transformer": "^0.4.0",
|
"@nestjs/class-transformer": "^0.4.0",
|
||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { IsString, IsNumber, IsOptional } from 'class-validator';
|
import { IsString, IsNumber, IsOptional } from 'class-validator';
|
||||||
import { Expose } from '@nestjs/class-transformer';
|
import { Expose } from '@nestjs/class-transformer';
|
||||||
|
import { Optional } from '@nestjs/common';
|
||||||
|
|
||||||
export class CreateMessageDto {
|
export class CreateMessageDto {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|
@ -16,6 +17,11 @@ export class CreateMessageDto {
|
||||||
@Expose()
|
@Expose()
|
||||||
time: number;
|
time: number;
|
||||||
|
|
||||||
|
@IsNumber()
|
||||||
|
@Expose()
|
||||||
|
@Optional()
|
||||||
|
date_time: number;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
@Expose()
|
@Expose()
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,11 @@ export class MessagesController {
|
||||||
return this.service.sendMessage(data);
|
return this.service.sendMessage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('')
|
||||||
|
save(@Body() data: CreateMessageDto) {
|
||||||
|
return this.service.create(data);
|
||||||
|
}
|
||||||
|
|
||||||
@Post('reply-message')
|
@Post('reply-message')
|
||||||
replyMessage(@Body() data: ReplyMessageDto) {
|
replyMessage(@Body() data: ReplyMessageDto) {
|
||||||
return this.service.replyMessage(data);
|
return this.service.replyMessage(data);
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,17 @@ import { MessagesController } from './messages.controller';
|
||||||
import { MessagesGateway } from './messages.gateway';
|
import { MessagesGateway } from './messages.gateway';
|
||||||
import { MessagesService } from './messages.service';
|
import { MessagesService } from './messages.service';
|
||||||
import { MessagesListener } from './messages.listener';
|
import { MessagesListener } from './messages.listener';
|
||||||
|
import { ZulipService } from './zulip.service';
|
||||||
|
import { HttpModule } from '@nestjs/axios';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([Message, Conversation])],
|
imports: [TypeOrmModule.forFeature([Message, Conversation]), HttpModule],
|
||||||
providers: [
|
providers: [
|
||||||
MessagesService,
|
MessagesService,
|
||||||
MessagesGateway,
|
MessagesGateway,
|
||||||
MessagesEventService,
|
MessagesEventService,
|
||||||
MessagesListener,
|
MessagesListener,
|
||||||
|
ZulipService,
|
||||||
],
|
],
|
||||||
controllers: [MessagesController],
|
controllers: [MessagesController],
|
||||||
exports: [MessagesGateway, MessagesService, MessagesEventService],
|
exports: [MessagesGateway, MessagesService, MessagesEventService],
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,12 @@ import { Conversation } from '@/entities/conversation.entity';
|
||||||
import { Message } from '@/entities/message.entity';
|
import { Message } from '@/entities/message.entity';
|
||||||
import AppResponse from '@/system/filters/response/app-response';
|
import AppResponse from '@/system/filters/response/app-response';
|
||||||
import { SystemLang } from '@/system/lang/system.lang';
|
import { SystemLang } from '@/system/lang/system.lang';
|
||||||
import { HttpStatus, Injectable, NotFoundException } from '@nestjs/common';
|
import {
|
||||||
|
BadRequestException,
|
||||||
|
HttpStatus,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { paginate, PaginateQuery } from 'nestjs-paginate';
|
import { paginate, PaginateQuery } from 'nestjs-paginate';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
@ -10,6 +15,7 @@ import { CreateMessageDto } from './dtos/create-message.dto';
|
||||||
import { ReplyMessageDto } from './dtos/reply-message.dto';
|
import { ReplyMessageDto } from './dtos/reply-message.dto';
|
||||||
import { SendMessageDto } from './dtos/send-message.dto';
|
import { SendMessageDto } from './dtos/send-message.dto';
|
||||||
import { MessagesEventService } from './messages-event.service';
|
import { MessagesEventService } from './messages-event.service';
|
||||||
|
import { ZulipService } from './zulip.service';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MessagesService {
|
export class MessagesService {
|
||||||
constructor(
|
constructor(
|
||||||
|
|
@ -17,7 +23,8 @@ export class MessagesService {
|
||||||
readonly repo: Repository<Message>,
|
readonly repo: Repository<Message>,
|
||||||
@InjectRepository(Conversation)
|
@InjectRepository(Conversation)
|
||||||
readonly conversationRepo: Repository<Conversation>,
|
readonly conversationRepo: Repository<Conversation>,
|
||||||
private event: MessagesEventService,
|
private readonly event: MessagesEventService,
|
||||||
|
private readonly zulupService: ZulipService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async index(query: PaginateQuery) {
|
async index(query: PaginateQuery) {
|
||||||
|
|
@ -48,16 +55,45 @@ export class MessagesService {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return existing; // hoặc throw error nếu muốn
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const conversation = await this.conversationRepo.findOne({
|
||||||
|
where: { id: dto.room_id },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!conversation)
|
||||||
|
throw new BadRequestException(
|
||||||
|
AppResponse.toResponse(null, {
|
||||||
|
message: SystemLang.getText('messages', 'not_found'),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const entity = this.repo.create({
|
const entity = this.repo.create({
|
||||||
...dto,
|
...dto,
|
||||||
time,
|
time,
|
||||||
time_raw: dto.time,
|
time_raw: dto.time,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.repo.save(entity);
|
const result = await this.repo.save(entity);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
if (
|
||||||
|
!conversation.name.includes(process.env.GROUP_PREFIX) ||
|
||||||
|
conversation.type !== 'group'
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!conversation) return;
|
||||||
|
|
||||||
|
await this.zulupService.sendMessageToTopic(
|
||||||
|
process.env.ZULIP_STREAMS_NAME,
|
||||||
|
conversation.name,
|
||||||
|
result.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkCreate(dtos: CreateMessageDto[]): Promise<Message[]> {
|
async bulkCreate(dtos: CreateMessageDto[]): Promise<Message[]> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { HttpService } from '@nestjs/axios';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ZulipService {
|
||||||
|
private readonly logger = new Logger(ZulipService.name);
|
||||||
|
|
||||||
|
constructor(private readonly httpService: HttpService) {}
|
||||||
|
|
||||||
|
async sendMessageToTopic(stream: string, topic: string, content: string) {
|
||||||
|
const url = process.env.ZULIP_API_URL;
|
||||||
|
const botEmail = process.env.ZULIP_BOT_EMAIL;
|
||||||
|
const apiKey = process.env.ZULIP_API_KEY;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await firstValueFrom(
|
||||||
|
this.httpService.post(
|
||||||
|
url,
|
||||||
|
new URLSearchParams({
|
||||||
|
type: 'stream',
|
||||||
|
to: stream,
|
||||||
|
topic: topic,
|
||||||
|
content: content,
|
||||||
|
}).toString(),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
username: botEmail,
|
||||||
|
password: apiKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.log(`Message sent to stream "${stream}" topic "${topic}"`);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
'Failed to send message to Zulip',
|
||||||
|
error?.response?.data || error.message,
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue