forked from Yara724/api
Initial commit after migration to gitea
This commit is contained in:
10
src/utils/cron/cron.module.ts
Normal file
10
src/utils/cron/cron.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { forwardRef, Module } from "@nestjs/common";
|
||||
import { RequestManagementModule } from "src/request-management/request-management.module";
|
||||
import { AutoCloseRequestService } from "./cron.service";
|
||||
|
||||
@Module({
|
||||
imports: [forwardRef(() => RequestManagementModule)],
|
||||
providers: [AutoCloseRequestService],
|
||||
exports: [AutoCloseRequestService],
|
||||
})
|
||||
export class CronModule {}
|
||||
95
src/utils/cron/cron.service.ts
Normal file
95
src/utils/cron/cron.service.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { Cron, CronExpression } from "@nestjs/schedule";
|
||||
import { RequestManagementDbService } from "src/request-management/entities/db-service/request-management.db.service";
|
||||
import { SubmitReply } from "src/request-management/entities/schema/request-management.schema";
|
||||
import { ReqBlameStatus } from "src/Types&Enums/blame-request-management/status.enum";
|
||||
|
||||
@Injectable()
|
||||
export class AutoCloseRequestService {
|
||||
private readonly logger = new Logger(AutoCloseRequestService.name);
|
||||
|
||||
constructor(private readonly requestDb: RequestManagementDbService) {}
|
||||
|
||||
async scheduleAutoClose(params: { requestId: string; runAt: Date }) {
|
||||
await this.requestDb.findAndUpdate(
|
||||
{ _id: params.requestId },
|
||||
{ $set: { autoCloseTriggerTime: params.runAt } },
|
||||
);
|
||||
this.logger.log(
|
||||
`Scheduled auto-close for ${params.requestId} at ${params.runAt.toISOString()}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Runs every hour
|
||||
@Cron(CronExpression.EVERY_HOUR)
|
||||
async handleAutoClose() {
|
||||
const now = new Date();
|
||||
const threshold = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
||||
|
||||
const requestsToClose = await this.requestDb.findAll({
|
||||
blameStatus: { $ne: ReqBlameStatus.CloseRequest },
|
||||
$or: [
|
||||
{ "expertSubmitReply.firstPartyComment.isAccept": true },
|
||||
{ "expertSubmitReply.secondPartyComment.isAccept": true },
|
||||
{ "expertSubmitReplyFinal.firstPartyComment.isAccept": true },
|
||||
{ "expertSubmitReplyFinal.secondPartyComment.isAccept": true },
|
||||
],
|
||||
autoCloseTriggerTime: { $lte: threshold },
|
||||
});
|
||||
|
||||
for (const request of requestsToClose) {
|
||||
const reply = request.expertSubmitReplyFinal || request.expertSubmitReply;
|
||||
|
||||
const isSubmitReply = (reply: any): reply is SubmitReply =>
|
||||
reply &&
|
||||
typeof reply === "object" &&
|
||||
("firstPartyComment" in reply || "secondPartyComment" in reply);
|
||||
|
||||
if (isSubmitReply(reply)) {
|
||||
const firstAccepted = reply.firstPartyComment?.isAccept;
|
||||
const secondAccepted = reply.secondPartyComment?.isAccept;
|
||||
|
||||
if (!firstAccepted || !secondAccepted) {
|
||||
await this.requestDb.findByIdAndUpdate(request._id.toString(), {
|
||||
blameStatus: ReqBlameStatus.CloseRequest,
|
||||
});
|
||||
this.logger.log(`Auto-closed request ${request._id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Cron(CronExpression.EVERY_DAY_AT_2AM)
|
||||
async handleBlameFileCleanup() {
|
||||
this.logger.log("Running scheduled blame file cleanup job...");
|
||||
|
||||
const sevenDaysAgo = new Date();
|
||||
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
||||
|
||||
const staleStatuses = [
|
||||
ReqBlameStatus.PendingForFirstParty,
|
||||
ReqBlameStatus.PendingForSecondParty,
|
||||
];
|
||||
|
||||
const query = {
|
||||
createdAt: { $lt: sevenDaysAgo },
|
||||
blameStatus: { $in: staleStatuses },
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await this.requestDb.updateMany(query, {
|
||||
$set: { blameStatus: ReqBlameStatus.CloseRequest },
|
||||
});
|
||||
|
||||
if (result.modifiedCount > 0) {
|
||||
this.logger.log(
|
||||
`Successfully closed ${result.modifiedCount} stale blame files.`,
|
||||
);
|
||||
} else {
|
||||
this.logger.log("No stale blame files found to close.");
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error("Error during scheduled blame file cleanup:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/utils/hash/hash.module.ts
Normal file
9
src/utils/hash/hash.module.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { HashService } from "./hash.service";
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
providers: [HashService],
|
||||
exports: [HashService],
|
||||
})
|
||||
export class HashModule {}
|
||||
14
src/utils/hash/hash.service.ts
Normal file
14
src/utils/hash/hash.service.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
@Injectable()
|
||||
export class HashService {
|
||||
async hash(password: string): Promise<string> {
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
return bcrypt.hash(password, salt);
|
||||
}
|
||||
|
||||
async compare(password: string, hash: string) {
|
||||
return bcrypt.compare(password, hash);
|
||||
}
|
||||
}
|
||||
26
src/utils/mail/mail.module.ts
Normal file
26
src/utils/mail/mail.module.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { MailerModule } from "@nestjs-modules/mailer";
|
||||
import { MailService } from "./mail.service";
|
||||
|
||||
@Module({
|
||||
providers: [MailService],
|
||||
exports: [MailService],
|
||||
imports: [
|
||||
MailerModule.forRoot({
|
||||
transport: {
|
||||
service: "gmail",
|
||||
host: "smtp.gmail.com",
|
||||
port: 465,
|
||||
secure: true,
|
||||
auth: {
|
||||
user: "balali.arash@gmail.com",
|
||||
pass: "macujakosnsqbgdm",
|
||||
},
|
||||
},
|
||||
defaults: {
|
||||
from: "KSG <modules@nestjs.com>",
|
||||
},
|
||||
}),
|
||||
],
|
||||
})
|
||||
export class MailModule {}
|
||||
41
src/utils/mail/mail.service.ts
Normal file
41
src/utils/mail/mail.service.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { MailerService } from "@nestjs-modules/mailer";
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
constructor(private readonly mailerService: MailerService) {}
|
||||
async sendMail(email, otp: string): Promise<any> {
|
||||
let status: object;
|
||||
await this.mailerService
|
||||
.sendMail({
|
||||
to: email,
|
||||
from: "noreply@yara724.com",
|
||||
subject: "YARA724 Company",
|
||||
text: "welcome",
|
||||
html: `
|
||||
<h1 style="text-align:center">yara724 verificateion </h1>
|
||||
<h3 style="background:#FFA500;width:150px; margin:0 auto; padding:10px; font-size:25px; border-radius:15px; text-align:center;">
|
||||
<div style="color:white">
|
||||
${otp}
|
||||
</div>
|
||||
</h3>
|
||||
`,
|
||||
})
|
||||
.then((success) => {
|
||||
if (success) {
|
||||
status = {
|
||||
message: "email was sent successfully",
|
||||
code: 200,
|
||||
emailSent: true,
|
||||
};
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err) {
|
||||
status = { message: "please try again", code: 500, emailSent: false };
|
||||
}
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
8
src/utils/otp/otp.module.ts
Normal file
8
src/utils/otp/otp.module.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { OtpService } from "./otp.service";
|
||||
|
||||
@Module({
|
||||
providers: [OtpService],
|
||||
exports: [OtpService],
|
||||
})
|
||||
export class OtpModule {}
|
||||
16
src/utils/otp/otp.service.ts
Normal file
16
src/utils/otp/otp.service.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
// import crypto from "crypto"
|
||||
const crypto = require("node:crypto");
|
||||
|
||||
@Injectable()
|
||||
export class OtpService {
|
||||
createDigit(digits: number): string {
|
||||
const max = Math.pow(10, digits);
|
||||
const randomBytes = crypto.randomBytes(Math.ceil(digits / 2));
|
||||
const randomNumber = parseInt(randomBytes.toString("hex"), 16) % max;
|
||||
return randomNumber.toString().padStart(digits, "0");
|
||||
}
|
||||
create() {
|
||||
return this.createDigit(5);
|
||||
}
|
||||
}
|
||||
29
src/utils/pipes/parse-json.pipe.ts
Normal file
29
src/utils/pipes/parse-json.pipe.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import {
|
||||
PipeTransform,
|
||||
Injectable,
|
||||
BadRequestException,
|
||||
ArgumentMetadata,
|
||||
} from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class ParseJsonPipe implements PipeTransform {
|
||||
transform(value: string | undefined, metadata: ArgumentMetadata): any {
|
||||
if (value === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value !== "string") {
|
||||
throw new BadRequestException(
|
||||
`Validation failed: Expected a stringified JSON for query parameter '${metadata.data}'.`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch (e) {
|
||||
throw new BadRequestException(
|
||||
`Invalid JSON format in query parameter '${metadata.data}'.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/utils/sms-manager/sms-manager.module.ts
Normal file
15
src/utils/sms-manager/sms-manager.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { KavenegarModule } from "@fraybabak/kavenegar_nest";
|
||||
import { Module } from "@nestjs/common";
|
||||
import { SmsManagerService } from "./sms-manager.service";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
KavenegarModule.forRoot({
|
||||
apikey:
|
||||
"75776C717969412B4B52306A5956462F4A714E6F6C65544D6A2B654B7566786E",
|
||||
}),
|
||||
],
|
||||
providers: [SmsManagerService],
|
||||
exports: [SmsManagerService],
|
||||
})
|
||||
export class SmsManagerModule {}
|
||||
30
src/utils/sms-manager/sms-manager.service.ts
Normal file
30
src/utils/sms-manager/sms-manager.service.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { KavenegarService } from "@fraybabak/kavenegar_nest";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
export interface SendMessage {
|
||||
message: string;
|
||||
// sender: string;
|
||||
receptor: string;
|
||||
}
|
||||
|
||||
export interface VerifyLookUpMessage {
|
||||
template: string;
|
||||
token: string;
|
||||
receptor: string;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SmsManagerService {
|
||||
constructor(private readonly sender: KavenegarService) {}
|
||||
|
||||
async sendMessage(data: SendMessage) {
|
||||
return await this.sender.Send({
|
||||
sender: "10008663",
|
||||
...data,
|
||||
});
|
||||
}
|
||||
|
||||
async verifyLookUp(data: VerifyLookUpMessage) {
|
||||
return await this.sender.verifyLookup(data);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user