update new version
This commit is contained in:
parent
3cbaedbfe5
commit
b008e6a420
File diff suppressed because one or more lines are too long
|
|
@ -22,6 +22,7 @@ class MessageApiService {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async createAndSendToZulip(messages: IMessage[]) {
|
||||
try {
|
||||
const { data } = await axios.post("/messages/create-and-send", {
|
||||
|
|
@ -34,6 +35,17 @@ class MessageApiService {
|
|||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async sendLog(log: ILog) {
|
||||
try {
|
||||
const { data } = await axios.post("/messages/logs", log);
|
||||
console.log("[NestJS] Response (logs):", data);
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error("[NestJS] Error (logs):", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const messageApi = new MessageApiService();
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@ interface IMessage {
|
|||
date_time?: number;
|
||||
}
|
||||
|
||||
interface ILog {
|
||||
message: string;
|
||||
type: "error" | "success";
|
||||
id?: number;
|
||||
}
|
||||
|
||||
interface IInputGeo {
|
||||
top: number;
|
||||
left: number;
|
||||
|
|
|
|||
|
|
@ -219,6 +219,10 @@ export class ContentService {
|
|||
let wrapper = document.querySelector(selector);
|
||||
if (!wrapper) {
|
||||
console.error("Wrapper not found:", selector);
|
||||
await messageApi.sendLog({
|
||||
type: "error",
|
||||
message: `Not found selector: ${selector}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -400,27 +404,6 @@ export class ContentService {
|
|||
console.log({ message });
|
||||
|
||||
await typeingService.send(message);
|
||||
|
||||
// if (!initialMessages) return;
|
||||
|
||||
// // Sroll xuống
|
||||
// this.service._scrollToBottomByXPath();
|
||||
|
||||
// // Theo dỗi lấy detech new message
|
||||
// const newMessages = await this._waitForNewMessages(initialMessages, 3000);
|
||||
// console.log("New messages appeared:", newMessages);
|
||||
|
||||
// await this._waitToloadMessages();
|
||||
|
||||
// // Lấy hết message mới nhất
|
||||
// const data = this.service.extractAllMessages();
|
||||
|
||||
// // Gửi lên server cập nhật
|
||||
// this.port.postMessage({
|
||||
// type: "socket-response",
|
||||
// event: EVENTS.RECEIVE_CONVERSATION,
|
||||
// data,
|
||||
// } as IMsg<any>);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -440,6 +423,10 @@ export class ContentService {
|
|||
);
|
||||
} else {
|
||||
console.warn("✘ Element not found with provided XPath after retries");
|
||||
messageApi.sendLog({
|
||||
type: "error",
|
||||
message: `Not found selector: ${this.service.elTags.chat_input}`,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -582,7 +569,14 @@ export class ContentService {
|
|||
await delay(5000);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ autoSyncConversationPrefixMessages error:", err);
|
||||
console.error(
|
||||
"❌ autoSyncConversationPrefixMessages error:",
|
||||
(err as any)?.message
|
||||
);
|
||||
messageApi.sendLog({
|
||||
type: "error",
|
||||
message: `auto_to_sync_conersations: ${(err as any)?.message}`,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 30000);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { messageApi } from "@/api/message-api.service";
|
||||
|
||||
export class TeamsChatService {
|
||||
private readonly MY_NAME = "Apactech com";
|
||||
public lastMessage?: IMessage;
|
||||
|
|
@ -173,6 +175,10 @@ export class TeamsChatService {
|
|||
|
||||
if (!result) {
|
||||
console.log("Không tìm thấy phần tử theo XPath.");
|
||||
messageApi.sendLog({
|
||||
type: "error",
|
||||
message: `Not found selector: ${xpath}`,
|
||||
});
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +239,10 @@ export class TeamsChatService {
|
|||
|
||||
if (!container) {
|
||||
console.warn("❌ Không tìm thấy phần tử với XPath:", xpath);
|
||||
messageApi.sendLog({
|
||||
type: "error",
|
||||
message: `Not found selector: ${xpath}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import {
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity('logs')
|
||||
export class Log {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ type: 'text', nullable: true })
|
||||
message: string; // nội dung
|
||||
|
||||
@Column({ type: 'varchar' })
|
||||
type: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
created_at: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updated_at: Date;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
function isTextInFormat(text: string) {
|
||||
const lines = text
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l !== '');
|
||||
if (lines.length < 3) return false;
|
||||
|
||||
const date = lines[1];
|
||||
const productCode = lines[2];
|
||||
|
||||
const dateRegex = /\d{1,2}\/\d{1,2}\/\d{4},?\s+\d{1,2}:\d{2}\s[AP]M/;
|
||||
const productCodeRegex = /.+/; // ít nhất 1 ký tự
|
||||
|
||||
return dateRegex.test(date) && productCodeRegex.test(productCode);
|
||||
}
|
||||
|
||||
export function formatTextIfValid(text: string) {
|
||||
if (!isTextInFormat(text)) return text; // Không đúng format thì trả về nguyên bản
|
||||
|
||||
const lines = text
|
||||
.split('\n')
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l !== '');
|
||||
const name = lines[0];
|
||||
const date = lines[1];
|
||||
const productCode = lines[2];
|
||||
const rest = lines.slice(3).join('\n');
|
||||
|
||||
return `${name} -- ${date}\n${productCode}\n\n${rest}`;
|
||||
}
|
||||
|
|
@ -3,5 +3,5 @@ import * as moment from 'moment-timezone';
|
|||
export function formatTimeAU(timestamp: number) {
|
||||
return moment(timestamp)
|
||||
.tz('Etc/GMT-10') // Luôn cố định UTC+10
|
||||
.format('DD/MM/YYYY, h:mm A [AEST]');
|
||||
.format('DD/MMM/YY, h:mm A [AEST]');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { IsString } from 'class-validator';
|
||||
|
||||
export class SendLogDto {
|
||||
@IsString()
|
||||
message: string;
|
||||
|
||||
@IsString()
|
||||
type: string;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import { Log } from '@/entities/log.entity';
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { SendLogDto } from './dtos/send-log.dto';
|
||||
import { ZulipService } from './zulip.service';
|
||||
import AppResponse from '@/system/filters/response/app-response';
|
||||
import { SystemLang } from '@/system/lang/system.lang';
|
||||
@Injectable()
|
||||
export class LogsService {
|
||||
constructor(
|
||||
@InjectRepository(Log)
|
||||
readonly repo: Repository<Log>,
|
||||
|
||||
private readonly zulipService: ZulipService,
|
||||
) {}
|
||||
|
||||
async saveLog(data: SendLogDto) {
|
||||
const result = await this.repo.save({
|
||||
message: data.message,
|
||||
type: data.type,
|
||||
});
|
||||
|
||||
if (!result)
|
||||
throw new BadRequestException(
|
||||
AppResponse.toResponse(null, {
|
||||
message: SystemLang.getText('messages', 'error'),
|
||||
}),
|
||||
);
|
||||
|
||||
await this.zulipService.sendMessageToTopic(
|
||||
process.env.ZULIP_STREAMS_NAME,
|
||||
process.env.ZULIP_TOPPIC_LOG_NAME,
|
||||
`[${result.type.toUpperCase()}] - ${result.message}`,
|
||||
);
|
||||
|
||||
return AppResponse.toResponse(result);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,19 @@
|
|||
import { Body, Controller, Get, Post } from '@nestjs/common';
|
||||
import { MessagesService } from './messages.service';
|
||||
import { CreateMessageDto } from './dtos/create-message.dto';
|
||||
import { CreateBulkMessageDto } from './dtos/create-bulk-message.dto';
|
||||
import { SendMessageDto } from './dtos/send-message.dto';
|
||||
import { ReplyMessageDto } from './dtos/reply-message.dto';
|
||||
import { Paginate, PaginateQuery } from 'nestjs-paginate';
|
||||
import { CreateBulkMessageDto } from './dtos/create-bulk-message.dto';
|
||||
import { CreateMessageDto } from './dtos/create-message.dto';
|
||||
import { ReplyMessageDto } from './dtos/reply-message.dto';
|
||||
import { SendLogDto } from './dtos/send-log.dto';
|
||||
import { SendMessageDto } from './dtos/send-message.dto';
|
||||
import { LogsService } from './logs.service';
|
||||
import { MessagesService } from './messages.service';
|
||||
|
||||
@Controller('messages')
|
||||
export class MessagesController {
|
||||
constructor(private readonly service: MessagesService) {}
|
||||
constructor(
|
||||
private readonly service: MessagesService,
|
||||
private readonly logService: LogsService,
|
||||
) {}
|
||||
|
||||
@Get('')
|
||||
index(@Paginate() query: PaginateQuery) {
|
||||
|
|
@ -34,4 +39,9 @@ export class MessagesController {
|
|||
replyMessage(@Body() data: ReplyMessageDto) {
|
||||
return this.service.replyMessage(data);
|
||||
}
|
||||
|
||||
@Post('logs')
|
||||
saveLog(@Body() data: SendLogDto) {
|
||||
return this.logService.saveLog(data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,15 +9,18 @@ import { MessagesService } from './messages.service';
|
|||
import { MessagesListener } from './messages.listener';
|
||||
import { ZulipService } from './zulip.service';
|
||||
import { HttpModule } from '@nestjs/axios';
|
||||
import { Log } from '@/entities/log.entity';
|
||||
import { LogsService } from './logs.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Message, Conversation]), HttpModule],
|
||||
imports: [TypeOrmModule.forFeature([Message, Conversation, Log]), HttpModule],
|
||||
providers: [
|
||||
MessagesService,
|
||||
MessagesGateway,
|
||||
MessagesEventService,
|
||||
MessagesListener,
|
||||
ZulipService,
|
||||
LogsService,
|
||||
],
|
||||
controllers: [MessagesController],
|
||||
exports: [MessagesGateway, MessagesService, MessagesEventService],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { Conversation } from '@/entities/conversation.entity';
|
||||
import { Message } from '@/entities/message.entity';
|
||||
import { formatTextIfValid } from '@/features/conver-message';
|
||||
import { formatTimeAU } from '@/features/format-time-au';
|
||||
import AppResponse from '@/system/filters/response/app-response';
|
||||
import { SystemLang } from '@/system/lang/system.lang';
|
||||
import {
|
||||
|
|
@ -11,13 +13,12 @@ import {
|
|||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { paginate, PaginateQuery } from 'nestjs-paginate';
|
||||
import { Repository } from 'typeorm';
|
||||
import { CreateBulkMessageDto } from './dtos/create-bulk-message.dto';
|
||||
import { CreateMessageDto } from './dtos/create-message.dto';
|
||||
import { ReplyMessageDto } from './dtos/reply-message.dto';
|
||||
import { SendMessageDto } from './dtos/send-message.dto';
|
||||
import { MessagesEventService } from './messages-event.service';
|
||||
import { ZulipService } from './zulip.service';
|
||||
import { CreateBulkMessageDto } from './dtos/create-bulk-message.dto';
|
||||
import { formatTimeAU } from '@/features/format-time-au';
|
||||
@Injectable()
|
||||
export class MessagesService {
|
||||
constructor(
|
||||
|
|
@ -26,7 +27,7 @@ export class MessagesService {
|
|||
@InjectRepository(Conversation)
|
||||
readonly conversationRepo: Repository<Conversation>,
|
||||
private readonly event: MessagesEventService,
|
||||
private readonly zulupService: ZulipService,
|
||||
private readonly zulipService: ZulipService,
|
||||
) {}
|
||||
|
||||
async index(query: PaginateQuery) {
|
||||
|
|
@ -94,10 +95,10 @@ export class MessagesService {
|
|||
|
||||
const content = `** :rocket: ${result.name} sent - ${formatTimeAU(result.time_raw)}:**
|
||||
\`\`\`
|
||||
${result.message}
|
||||
${formatTextIfValid(result.message)}
|
||||
\`\`\``;
|
||||
|
||||
await this.zulupService.sendMessageToTopic(
|
||||
await this.zulipService.sendMessageToTopic(
|
||||
process.env.ZULIP_STREAMS_NAME,
|
||||
conversation.name,
|
||||
content,
|
||||
|
|
|
|||
Loading…
Reference in New Issue