fix spam message
This commit is contained in:
parent
fe4d22f361
commit
4d2c39c053
|
|
@ -118,10 +118,6 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (!isIBid(data)) {
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
|
|
@ -200,7 +196,7 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
</Box>
|
||||
<Box className="flex items-center gap-4">
|
||||
<Button
|
||||
rightSection={<IconImageInPicture size={14}/>}
|
||||
rightSection={<IconImageInPicture size={14} />}
|
||||
size="xs"
|
||||
color="green"
|
||||
onClick={open}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"createdAt":1747107717780}
|
||||
{"createdAt":1747191706164}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
"@nestjs/mapped-types": "*",
|
||||
"@nestjs/platform-express": "^10.4.15",
|
||||
"@nestjs/platform-socket.io": "^11.0.11",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/throttler": "^6.4.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nestjs/websockets": "^11.0.11",
|
||||
|
|
@ -51,7 +52,7 @@
|
|||
"@types/jest": "^29.5.2",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/node": "^20.17.46",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
|
|
@ -2458,6 +2459,19 @@
|
|||
"rxjs": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/schedule": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/schedule/-/schedule-6.0.0.tgz",
|
||||
"integrity": "sha512-aQySMw6tw2nhitELXd3EiRacQRgzUKD9mFcUZVOJ7jPLqIBvXOyvRWLsK9SdurGA+jjziAlMef7iB5ZEFFoQpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron": "4.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
||||
"@nestjs/core": "^10.0.0 || ^11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@nestjs/schematics": {
|
||||
"version": "10.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.2.3.tgz",
|
||||
|
|
@ -3007,6 +3021,12 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.6.2.tgz",
|
||||
"integrity": "sha512-R/BdP7OxEMc44l2Ex5lSXHoIXTB2JLNa3y2QISIbr58U/YcsffyQrYW//hZSdrfxrjRZj3GcUoxMPGdO8gSYuw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/methods": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
|
||||
|
|
@ -3032,9 +3052,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.17.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.24.tgz",
|
||||
"integrity": "sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==",
|
||||
"version": "20.17.46",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.46.tgz",
|
||||
"integrity": "sha512-0PQHLhZPWOxGW4auogW0eOQAuNIlCYvibIpG67ja0TOJ6/sehu+1en7sfceUn+QQtx4Rk3GxbLNwPh0Cav7TWw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
|
|
@ -4875,6 +4895,19 @@
|
|||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-4.3.0.tgz",
|
||||
"integrity": "sha512-ciiYNLfSlF9MrDqnbMdRWFiA6oizSF7kA1osPP9lRzNu0Uu+AWog1UKy7SkckiDY2irrNjeO6qLyKnXC8oxmrw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/luxon": "~3.6.0",
|
||||
"luxon": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
|
|
@ -8335,6 +8368,15 @@
|
|||
"url": "https://github.com/sponsors/wellwelwel"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.6.1.tgz",
|
||||
"integrity": "sha512-tJLxrKJhO2ukZ5z0gyjY1zPh3Rh88Ej9P7jNrZiHMUXHae1yvI2imgOZtL1TO8TW6biMMKfTtAOoEJANgtWBMQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
"@nestjs/mapped-types": "*",
|
||||
"@nestjs/platform-express": "^10.4.15",
|
||||
"@nestjs/platform-socket.io": "^11.0.11",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
"@nestjs/throttler": "^6.4.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nestjs/websockets": "^11.0.11",
|
||||
|
|
@ -67,7 +68,7 @@
|
|||
"@types/jest": "^29.5.2",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/multer": "^1.4.12",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/node": "^20.17.46",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -11,6 +12,7 @@ import { EventEmitterModule } from '@nestjs/event-emitter';
|
|||
wildcard: true,
|
||||
global: true,
|
||||
}),
|
||||
ScheduleModule.forRoot()
|
||||
],
|
||||
})
|
||||
export class AppConfigsModule {}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ import { SendMessageHistoriesService } from './services/send-message-histories.s
|
|||
import { WebBidsService } from './services/web-bids.service';
|
||||
import { DashboardService } from './services/dashboard.service';
|
||||
import { AdminDashboardController } from './controllers/admin/admin-dashboard.controller';
|
||||
import { TasksService } from './services/tasks.servise';
|
||||
import { ConfigsService } from './services/configs.service';
|
||||
import { Config } from './entities/configs.entity';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
|
@ -36,6 +39,7 @@ import { AdminDashboardController } from './controllers/admin/admin-dashboard.co
|
|||
OutBidLog,
|
||||
WebBid,
|
||||
SendMessageHistory,
|
||||
Config
|
||||
]),
|
||||
// AuthModule,
|
||||
AdminsModule,
|
||||
|
|
@ -64,6 +68,8 @@ import { AdminDashboardController } from './controllers/admin/admin-dashboard.co
|
|||
SendMessageHistoriesService,
|
||||
ImapService,
|
||||
DashboardService,
|
||||
TasksService,
|
||||
ConfigsService
|
||||
],
|
||||
exports: [BotTelegramApi, SendMessageHistoriesService, BidsService],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import { Column, Entity, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
||||
import { Timestamp } from './timestamp';
|
||||
|
||||
@Entity('configs')
|
||||
export class Config extends Timestamp {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
||||
@Column({ unique: true })
|
||||
key_name: string;
|
||||
|
||||
@Column({ nullable: true, default: true })
|
||||
value: string | null;
|
||||
|
||||
@Column()
|
||||
type: 'string' | 'number';
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, Unique } from 'typeorm';
|
||||
import { Timestamp } from './timestamp';
|
||||
import { Bid } from './bid.entity';
|
||||
|
||||
@Entity('send_message_histories')
|
||||
@Unique(['max_price', 'type', 'reserve_price'])
|
||||
export class SendMessageHistory extends Timestamp {
|
||||
@PrimaryGeneratedColumn('increment')
|
||||
id: number;
|
||||
|
|
@ -17,4 +18,10 @@ export class SendMessageHistory extends Timestamp {
|
|||
onDelete: 'CASCADE',
|
||||
})
|
||||
bid: Bid;
|
||||
|
||||
@Column({ default: 0, nullable: true })
|
||||
max_price: number;
|
||||
|
||||
@Column({ default: 0, nullable: true })
|
||||
reserve_price: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { Column } from 'nestjs-paginate/lib/helper';
|
|||
import { join } from 'path';
|
||||
import AppResponse from 'src/response/app-response';
|
||||
import { extractModelId, isTimeReached, subtractMinutes } from 'src/ultils';
|
||||
import { In, Repository } from 'typeorm';
|
||||
import { In, IsNull, Not, Repository } from 'typeorm';
|
||||
import { ClientUpdateBidDto } from '../dto/bid/client-update-bid.dto';
|
||||
import { CreateBidDto } from '../dto/bid/create-bid.dto';
|
||||
import { UpdateBidDto } from '../dto/bid/update-bid.dto';
|
||||
|
|
@ -57,7 +57,7 @@ export class BidsService {
|
|||
lot_id: true,
|
||||
close_time: true,
|
||||
name: [FilterOperator.ILIKE],
|
||||
status: true
|
||||
status: true,
|
||||
};
|
||||
|
||||
query.filter = AppResponse.processFilters(query.filter, filterableColumns);
|
||||
|
|
@ -524,4 +524,29 @@ export class BidsService {
|
|||
|
||||
return AppResponse.toResponse(true);
|
||||
}
|
||||
|
||||
async getNextBid(): Promise<Bid | null> {
|
||||
const all = await this.bidsRepo.find({
|
||||
where: { status: 'biding', close_time: Not(IsNull()) },
|
||||
relations: { web_bid: true },
|
||||
});
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
let nextBid = null;
|
||||
let minDiff = Infinity;
|
||||
|
||||
for (const bid of all) {
|
||||
const time = Date.parse(bid.close_time);
|
||||
if (!isNaN(time) && time >= now) {
|
||||
const diff = time - now;
|
||||
if (diff < minDiff) {
|
||||
minDiff = diff;
|
||||
nextBid = bid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nextBid;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Config } from '../entities/configs.entity';
|
||||
|
||||
@Injectable()
|
||||
export class ConfigsService {
|
||||
public static CONFIG_KEYS = {
|
||||
REFRESH_TOOL_TIME: 'REFRESH_TOOL_TIME',
|
||||
};
|
||||
|
||||
constructor(
|
||||
@InjectRepository(Config)
|
||||
readonly configRepo: Repository<Config>,
|
||||
private eventEmitter: EventEmitter2,
|
||||
) {}
|
||||
|
||||
async getConfig(key_name: keyof typeof ConfigsService.CONFIG_KEYS) {
|
||||
return await this.configRepo.findOne({ where: { key_name } }) || null;
|
||||
}
|
||||
|
||||
async setConfig(key_name: keyof typeof ConfigsService.CONFIG_KEYS, value: string) {
|
||||
return await this.configRepo.upsert(
|
||||
{ key_name, value },
|
||||
['key_name']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import { BidsService } from './bids.service';
|
||||
import { isTimeReached, subtractMinutes, subtractSeconds } from '@/ultils';
|
||||
import { ConfigsService } from './configs.service';
|
||||
import { DashboardService } from './dashboard.service';
|
||||
@Injectable()
|
||||
export class TasksService {
|
||||
private readonly logger = new Logger(TasksService.name);
|
||||
|
||||
constructor(
|
||||
private readonly bidsService: BidsService,
|
||||
private readonly configsService: ConfigsService,
|
||||
private readonly dashboadService: DashboardService,
|
||||
) {}
|
||||
|
||||
@Cron(CronExpression.EVERY_MINUTE)
|
||||
async handleCron() {
|
||||
const nextBid = await this.bidsService.getNextBid();
|
||||
|
||||
if (!nextBid) return;
|
||||
|
||||
const timeReset = subtractMinutes(nextBid.close_time, 20);
|
||||
|
||||
const timeToTracking = subtractSeconds(
|
||||
nextBid.close_time,
|
||||
nextBid.web_bid.early_tracking_seconds,
|
||||
);
|
||||
|
||||
if (!isTimeReached(timeReset) || isTimeReached(timeToTracking)) {
|
||||
console.log('Reset not allowed at this time');
|
||||
return;
|
||||
}
|
||||
|
||||
const lastestResetToolTime =
|
||||
await this.configsService.getConfig('REFRESH_TOOL_TIME');
|
||||
|
||||
if (lastestResetToolTime?.value) {
|
||||
const lastReset = Date.parse(lastestResetToolTime.value);
|
||||
const now = Date.now();
|
||||
|
||||
const diffInMs = now - lastReset;
|
||||
const diffInHours = diffInMs / (1000 * 60 * 60);
|
||||
const minimumHours = 2;
|
||||
|
||||
if (diffInHours < minimumHours) {
|
||||
console.log(`Last reset was less than ${minimumHours} hours ago`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Proceeding to reset tool for next bid:', nextBid);
|
||||
|
||||
await this.dashboadService.resetTool();
|
||||
|
||||
|
||||
const time = new Date().toUTCString()
|
||||
|
||||
await this.configsService.setConfig(
|
||||
'REFRESH_TOOL_TIME',
|
||||
time,
|
||||
);
|
||||
|
||||
console.log('Reset successfully at: ' + time);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -109,18 +109,40 @@ export class NotificationService {
|
|||
send_to: JSON.stringify(sendToData),
|
||||
});
|
||||
|
||||
await this.sendMessageRepo.save({
|
||||
bid: { id: bid.id },
|
||||
message: notification.message,
|
||||
type: bid.status,
|
||||
});
|
||||
try {
|
||||
const prevAnyMessage = await this.sendMessageRepo.findOne({
|
||||
where: {
|
||||
bid: { id: bid.id },
|
||||
message: notification.message,
|
||||
type: bid.status,
|
||||
max_price: bid.max_price,
|
||||
reserve_price: bid.reserve_price
|
||||
},
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(NAME_EVENTS.BID_STATUS, {
|
||||
bid: {
|
||||
...bid,
|
||||
status: 'out-bid',
|
||||
},
|
||||
notification,
|
||||
});
|
||||
if (prevAnyMessage) return;
|
||||
|
||||
await this.sendMessageRepo.save({
|
||||
bid: { id: bid.id },
|
||||
message: notification.message,
|
||||
type: bid.status,
|
||||
max_price: bid.max_price,
|
||||
reserve_price: bid.reserve_price
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(NAME_EVENTS.BID_STATUS, {
|
||||
bid: {
|
||||
...bid,
|
||||
status: 'out-bid',
|
||||
},
|
||||
notification,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(
|
||||
'%csrc/modules/notification/notification.service.ts:131 Error',
|
||||
'color: #007acc;',
|
||||
Error,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ export function subtractMinutes(timeStr: string, minutes: number) {
|
|||
return date.toISOString(); // Trả về dạng chuẩn ISO
|
||||
}
|
||||
|
||||
export function subtractSeconds(time: string, seconds: number) {
|
||||
const date = new Date(time);
|
||||
date.setSeconds(date.getSeconds() - seconds);
|
||||
return date.toUTCString();
|
||||
}
|
||||
|
||||
export function isTimeReached(targetTime: string) {
|
||||
const targetDate = new Date(targetTime);
|
||||
const now = new Date();
|
||||
|
|
|
|||
Loading…
Reference in New Issue