update new version

This commit is contained in:
Admin 2025-09-10 10:12:50 +07:00
parent 3cbaedbfe5
commit b008e6a420
13 changed files with 180 additions and 41 deletions

File diff suppressed because one or more lines are too long

View File

@ -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();

View File

@ -9,6 +9,12 @@ interface IMessage {
date_time?: number;
}
interface ILog {
message: string;
type: "error" | "success";
id?: number;
}
interface IInputGeo {
top: number;
left: number;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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}`;
}

View File

@ -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]');
}

View File

@ -0,0 +1,9 @@
import { IsString } from 'class-validator';
export class SendLogDto {
@IsString()
message: string;
@IsString()
type: string;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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],

View File

@ -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,