default
This commit is contained in:
parent
fd03804038
commit
86254bf7eb
10
backend/.env
10
backend/.env
@ -16,7 +16,7 @@ AWS_ENDPOINT_URL=https://eu2.contabostorage.com
|
||||
# SMTP_HOST=smtp.gmail.com
|
||||
# SMTP_PORT=587
|
||||
# SMTP_USER=taratur@gmail.com
|
||||
# SMTP_PASS=dziy nccc svgg bovb
|
||||
# SMTP_PASS=dziy nccc svgg bovb
|
||||
# EMAIL_FROM=taratur@gmail.com
|
||||
|
||||
SMTP_HOST=imk.mk
|
||||
@ -25,7 +25,13 @@ SMTP_USER=mailer@imk.mk
|
||||
SMTP_PASS=76Avtostoperski76
|
||||
SMTP_FROM=mailer@imk.mk
|
||||
# FRONTEND_URL=https://imk.mk
|
||||
# EMAIL_FROM=petrovskidimitar@yandex.com
|
||||
EMAIL_FROM=mailer@yandex.com
|
||||
|
||||
|
||||
ADMIN_EMAIL=taratur@gmail.com
|
||||
|
||||
|
||||
# default app ADMIN
|
||||
DEFAULT_ADMIN_EMAIL=taratur@gmail.com
|
||||
DEFAULT_ADMIN_PASSWORD=irina7654321
|
||||
DEFAULT_ADMIN_NAME=admin
|
||||
|
||||
@ -1,73 +1,47 @@
|
||||
<p align="center">
|
||||
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="200" alt="Nest Logo" /></a>
|
||||
</p>
|
||||
Add the necessary environment variables to your `.env` file:
|
||||
|
||||
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
|
||||
[circleci-url]: https://circleci.com/gh/nestjs/nest
|
||||
|
||||
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
|
||||
<p align="center">
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
|
||||
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
|
||||
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
|
||||
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
|
||||
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
|
||||
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
|
||||
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg"/></a>
|
||||
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
|
||||
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a>
|
||||
</p>
|
||||
<!--[](https://opencollective.com/nest#backer)
|
||||
[](https://opencollective.com/nest#sponsor)-->
|
||||
|
||||
## Description
|
||||
|
||||
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```env
|
||||
# Default Admin Configuration
|
||||
DEFAULT_ADMIN_EMAIL=admin@imk.com
|
||||
DEFAULT_ADMIN_PASSWORD=admin123456
|
||||
DEFAULT_ADMIN_NAME=System Admin
|
||||
```
|
||||
|
||||
## Running the app
|
||||
To use this setup:
|
||||
|
||||
1. The seed script will run automatically during deployment when you run:
|
||||
```bash
|
||||
# development
|
||||
$ npm run start
|
||||
|
||||
# watch mode
|
||||
$ npm run start:dev
|
||||
|
||||
# production mode
|
||||
$ npm run start:prod
|
||||
npx prisma db push
|
||||
npx prisma db seed
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
# unit tests
|
||||
$ npm run test
|
||||
|
||||
# e2e tests
|
||||
$ npm run test:e2e
|
||||
|
||||
# test coverage
|
||||
$ npm run test:cov
|
||||
2. Alternatively, you can manually trigger the initialization by making a POST request to:
|
||||
```
|
||||
POST /init/system
|
||||
```
|
||||
|
||||
## Support
|
||||
This gives you two ways to ensure the default admin user is created:
|
||||
1. Automatically during deployment via the seed script
|
||||
2. Manually via the initialization endpoint
|
||||
|
||||
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
|
||||
To deploy, you would:
|
||||
|
||||
## Stay in touch
|
||||
1. Set up your environment variables
|
||||
2. Run the database migrations
|
||||
3. Run the seed script
|
||||
```bash
|
||||
npm run prisma:deploy
|
||||
npm run prisma:seed
|
||||
```
|
||||
|
||||
- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
|
||||
- Website - [https://nestjs.com](https://nestjs.com/)
|
||||
- Twitter - [@nestframework](https://twitter.com/nestframework)
|
||||
The default admin credentials will be:
|
||||
- Email: admin@imk.com (or whatever you set in env)
|
||||
- Password: admin123456 (or whatever you set in env)
|
||||
|
||||
## License
|
||||
Make sure to:
|
||||
1. Change the default password after first login
|
||||
2. Use strong passwords in production
|
||||
3. Properly secure the initialization endpoint in production
|
||||
4. Keep your environment variables secure
|
||||
|
||||
Nest is [MIT licensed](LICENSE).
|
||||
This setup ensures you always have an admin user available after deployment while maintaining security and flexibility.
|
||||
|
||||
@ -17,7 +17,8 @@
|
||||
"test:watch": "jest --watch",
|
||||
"test:cov": "jest --coverage",
|
||||
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json"
|
||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||
"prisma:seed": "ts-node prisma/seed.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.679.0",
|
||||
|
||||
@ -1,23 +1,47 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
// backend/prisma/seed.ts
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const hashedPassword = await bcrypt.hash('admin123', 10);
|
||||
const defaultAdminEmail = process.env.DEFAULT_ADMIN_EMAIL || "admin@imk.com";
|
||||
const defaultAdminPassword =
|
||||
process.env.DEFAULT_ADMIN_PASSWORD || "admin123456";
|
||||
const defaultAdminName = process.env.DEFAULT_ADMIN_NAME || "System Admin";
|
||||
|
||||
const admin = await prisma.user.upsert({
|
||||
where: { email: 'admin@example.com' },
|
||||
update: {},
|
||||
create: {
|
||||
email: 'admin@example.com',
|
||||
name: 'Admin User',
|
||||
password: hashedPassword,
|
||||
isAdmin: true,
|
||||
},
|
||||
});
|
||||
try {
|
||||
// Check if admin already exists
|
||||
const existingAdmin = await prisma.user.findUnique({
|
||||
where: { email: defaultAdminEmail },
|
||||
});
|
||||
|
||||
console.log({ admin });
|
||||
if (!existingAdmin) {
|
||||
// Hash the password
|
||||
const hashedPassword = await bcrypt.hash(defaultAdminPassword, 10);
|
||||
|
||||
// Create the admin user
|
||||
const admin = await prisma.user.create({
|
||||
data: {
|
||||
email: defaultAdminEmail,
|
||||
name: defaultAdminName,
|
||||
password: hashedPassword,
|
||||
isAdmin: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Default admin user created:", {
|
||||
id: admin.id,
|
||||
email: admin.email,
|
||||
name: admin.name,
|
||||
});
|
||||
} else {
|
||||
console.log("Default admin user already exists");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error creating default admin:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@ -1,39 +1,31 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
import { Module } from "@nestjs/common";
|
||||
import { AppController } from "./app.controller";
|
||||
import { AppService } from "./app.service";
|
||||
import { AuthModule } from "./auth/auth.module";
|
||||
//import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { AdminModule } from './admin/admin.module';
|
||||
import { ClientModule } from './client/client.module';
|
||||
import { UploadService } from './upload/upload.service';
|
||||
import { DocumentsService } from './documents/documents.service';
|
||||
import { S3Service } from './s3/s3.service';
|
||||
import { S3Module } from './s3/s3.module';
|
||||
import { PrismaService } from './prisma/prisma.service';
|
||||
import { PrismaModule } from './prisma/prisma.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AuthController } from './auth/auth.controller';
|
||||
import { DocumentsController } from './documents/documents.controller';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { EmailModule } from './email/email.module';
|
||||
import { AdminModule } from "./admin/admin.module";
|
||||
import { ClientModule } from "./client/client.module";
|
||||
import { UploadService } from "./upload/upload.service";
|
||||
import { DocumentsService } from "./documents/documents.service";
|
||||
import { S3Service } from "./s3/s3.service";
|
||||
import { S3Module } from "./s3/s3.module";
|
||||
import { PrismaService } from "./prisma/prisma.service";
|
||||
import { PrismaModule } from "./prisma/prisma.module";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import { AuthController } from "./auth/auth.controller";
|
||||
import { DocumentsController } from "./documents/documents.controller";
|
||||
import { JwtModule } from "@nestjs/jwt";
|
||||
import { EmailModule } from "./email/email.module";
|
||||
import { InitModule } from "./init/init.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
// TypeOrmModule.forRoot({
|
||||
// type: 'postgres',
|
||||
// host: 'localhost',
|
||||
// port: 5432,
|
||||
// username: 'root',
|
||||
// password: 'admin',
|
||||
// database: 'imk',
|
||||
// synchronize: true,
|
||||
// }),
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
}),
|
||||
JwtModule.register({
|
||||
secret: process.env.JWT_SECRET,
|
||||
signOptions: { expiresIn: '1h' },
|
||||
signOptions: { expiresIn: "1h" },
|
||||
}),
|
||||
AuthModule,
|
||||
AdminModule,
|
||||
@ -41,6 +33,7 @@ import { EmailModule } from './email/email.module';
|
||||
S3Module,
|
||||
PrismaModule,
|
||||
EmailModule,
|
||||
InitModule,
|
||||
],
|
||||
controllers: [AppController, AuthController, DocumentsController],
|
||||
providers: [
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import * as nodemailer from 'nodemailer';
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import * as nodemailer from "nodemailer";
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
@ -9,29 +9,26 @@ export class EmailService {
|
||||
private readonly from: string;
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
console.log('Initializing EmailService...'); // Direct console log for debugging
|
||||
this.logger.log('Initializing EmailService...');
|
||||
console.log("Initializing EmailService..."); // Direct console log for debugging
|
||||
this.logger.log("Initializing EmailService...");
|
||||
|
||||
// Load config
|
||||
const host = this.configService.get<string>('SMTP_HOST');
|
||||
const port = this.configService.get<number>('SMTP_PORT');
|
||||
const user = this.configService.get<string>('SMTP_USER');
|
||||
const pass = this.configService.get<string>('SMTP_PASS');
|
||||
this.from = this.configService.get<string>('EMAIL_FROM');
|
||||
const host = this.configService.get<string>("SMTP_HOST");
|
||||
const port = this.configService.get<number>("SMTP_PORT");
|
||||
const user = this.configService.get<string>("SMTP_USER");
|
||||
const pass = this.configService.get<string>("SMTP_PASS");
|
||||
this.from = this.configService.get<string>("EMAIL_FROM");
|
||||
|
||||
console.log('Email Config:', { host, port, user, from: this.from }); // Direct console log
|
||||
this.logger.log('Email Config:', { host, port, user, from: this.from });
|
||||
console.log("Email Config:", { host, port, user, from: this.from }); // Direct console log
|
||||
this.logger.log("Email Config:", { host, port, user, from: this.from });
|
||||
|
||||
// Create transporter with Gmail settings
|
||||
this.transporter = nodemailer.createTransport({
|
||||
// host: 'smtp.gmail.com',
|
||||
// port: 587, // Use STARTTLS port
|
||||
// secure: false, // Use STARTTLS
|
||||
host: host,
|
||||
port: port,
|
||||
auth: { user, pass },
|
||||
debug: true, // Enable debug logs
|
||||
logger: true // Enable transport level logging
|
||||
debug: true, // Enable debug logs
|
||||
logger: true, // Enable transport level logging
|
||||
});
|
||||
|
||||
// Verify connection
|
||||
@ -40,16 +37,16 @@ export class EmailService {
|
||||
|
||||
private async verifyConnection() {
|
||||
try {
|
||||
console.log('Verifying SMTP connection...'); // Direct console log
|
||||
this.logger.log('Verifying SMTP connection...');
|
||||
|
||||
console.log("Verifying SMTP connection..."); // Direct console log
|
||||
this.logger.log("Verifying SMTP connection...");
|
||||
|
||||
const verification = await this.transporter.verify();
|
||||
|
||||
console.log('SMTP connection verified successfully!', verification); // Direct console log
|
||||
this.logger.log('SMTP connection verified successfully!', verification);
|
||||
|
||||
console.log("SMTP connection verified successfully!", verification); // Direct console log
|
||||
this.logger.log("SMTP connection verified successfully!", verification);
|
||||
} catch (error) {
|
||||
console.error('SMTP connection failed:', error); // Direct console log
|
||||
this.logger.error('SMTP connection failed:', {
|
||||
console.error("SMTP connection failed:", error); // Direct console log
|
||||
this.logger.error("SMTP connection failed:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -68,7 +65,7 @@ export class EmailService {
|
||||
const mailOptions = {
|
||||
from: `"IMK Platform" <${this.from}>`,
|
||||
to: userEmail,
|
||||
subject: 'Welcome to IMK Platform!',
|
||||
subject: "Welcome to IMK Platform!",
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2>Welcome to IMK Platform!</h2>
|
||||
@ -78,21 +75,21 @@ export class EmailService {
|
||||
<p>If you have any questions or need assistance, please don't hesitate to contact our support team.</p>
|
||||
<p>Best regards,<br>The IMK Team</p>
|
||||
</div>
|
||||
`
|
||||
`,
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('Attempting to send email with options:', mailOptions); // Direct console log
|
||||
this.logger.log('Attempting to send email with options:', {
|
||||
console.log("Attempting to send email with options:", mailOptions); // Direct console log
|
||||
this.logger.log("Attempting to send email with options:", {
|
||||
to: mailOptions.to,
|
||||
from: mailOptions.from,
|
||||
subject: mailOptions.subject
|
||||
subject: mailOptions.subject,
|
||||
});
|
||||
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
|
||||
console.log('Email sent successfully:', info); // Direct console log
|
||||
this.logger.log('Email sent successfully:', {
|
||||
|
||||
console.log("Email sent successfully:", info); // Direct console log
|
||||
this.logger.log("Email sent successfully:", {
|
||||
messageId: info.messageId,
|
||||
response: info.response,
|
||||
accepted: info.accepted,
|
||||
@ -100,8 +97,8 @@ export class EmailService {
|
||||
envelope: info.envelope,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to send email:', error); // Direct console log
|
||||
this.logger.error('Failed to send email:', {
|
||||
console.error("Failed to send email:", error); // Direct console log
|
||||
this.logger.error("Failed to send email:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -117,14 +114,18 @@ export class EmailService {
|
||||
userEmail: string,
|
||||
username: string,
|
||||
documentName: string,
|
||||
action: 'uploaded' | 'shared',
|
||||
action: "uploaded" | "shared",
|
||||
): Promise<void> {
|
||||
console.log('=== Starting document notification email process ===');
|
||||
this.logger.log('=== Starting document notification email process ===');
|
||||
console.log(`Preparing notification for ${userEmail}, document: ${documentName}, action: ${action}`);
|
||||
this.logger.log(`Preparing notification for ${userEmail}, document: ${documentName}, action: ${action}`);
|
||||
|
||||
const actionText = action === 'uploaded' ? 'uploaded' : 'shared with you';
|
||||
console.log("=== Starting document notification email process ===");
|
||||
this.logger.log("=== Starting document notification email process ===");
|
||||
console.log(
|
||||
`Preparing notification for ${userEmail}, document: ${documentName}, action: ${action}`,
|
||||
);
|
||||
this.logger.log(
|
||||
`Preparing notification for ${userEmail}, document: ${documentName}, action: ${action}`,
|
||||
);
|
||||
|
||||
const actionText = action === "uploaded" ? "uploaded" : "shared with you";
|
||||
const mailOptions = {
|
||||
from: `"IMK Platform" <${this.from}>`,
|
||||
to: userEmail,
|
||||
@ -142,31 +143,31 @@ export class EmailService {
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('Sending document notification email with options:', {
|
||||
console.log("Sending document notification email with options:", {
|
||||
to: mailOptions.to,
|
||||
from: mailOptions.from,
|
||||
subject: mailOptions.subject,
|
||||
documentName,
|
||||
action
|
||||
action,
|
||||
});
|
||||
this.logger.log('Sending document notification email with options:', {
|
||||
this.logger.log("Sending document notification email with options:", {
|
||||
to: mailOptions.to,
|
||||
from: mailOptions.from,
|
||||
subject: mailOptions.subject,
|
||||
documentName,
|
||||
action
|
||||
action,
|
||||
});
|
||||
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
|
||||
console.log('Document notification email sent successfully:', {
|
||||
|
||||
console.log("Document notification email sent successfully:", {
|
||||
messageId: info.messageId,
|
||||
response: info.response,
|
||||
accepted: info.accepted,
|
||||
rejected: info.rejected,
|
||||
envelope: info.envelope,
|
||||
});
|
||||
this.logger.log('Document notification email sent successfully:', {
|
||||
this.logger.log("Document notification email sent successfully:", {
|
||||
messageId: info.messageId,
|
||||
response: info.response,
|
||||
accepted: info.accepted,
|
||||
@ -174,8 +175,8 @@ export class EmailService {
|
||||
envelope: info.envelope,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to send document notification email:', error);
|
||||
this.logger.error('Failed to send document notification email:', {
|
||||
console.error("Failed to send document notification email:", error);
|
||||
this.logger.error("Failed to send document notification email:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -188,12 +189,12 @@ export class EmailService {
|
||||
}
|
||||
|
||||
async sendPasswordResetNotification(email: string, name: string) {
|
||||
this.logger.log('Sending password reset notification email to:', email);
|
||||
this.logger.log("Sending password reset notification email to:", email);
|
||||
|
||||
const mailOptions = {
|
||||
from: this.from,
|
||||
to: email,
|
||||
subject: 'Your Password Has Been Reset',
|
||||
subject: "Your Password Has Been Reset",
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2>Password Reset Notification</h2>
|
||||
@ -206,12 +207,15 @@ export class EmailService {
|
||||
};
|
||||
|
||||
try {
|
||||
this.logger.debug('Attempting to send password reset notification...');
|
||||
this.logger.debug("Attempting to send password reset notification...");
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
this.logger.log('Password reset notification sent successfully:', info.response);
|
||||
this.logger.log(
|
||||
"Password reset notification sent successfully:",
|
||||
info.response,
|
||||
);
|
||||
return info;
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to send password reset notification:', {
|
||||
this.logger.error("Failed to send password reset notification:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -222,13 +226,13 @@ export class EmailService {
|
||||
}
|
||||
|
||||
async sendPasswordResetEmail(email: string, name: string, token: string) {
|
||||
this.logger.log('Sending password reset email to:', email);
|
||||
this.logger.log("Sending password reset email to:", email);
|
||||
|
||||
const resetLink = `${process.env.FRONTEND_URL}/reset-password?token=${token}`;
|
||||
const mailOptions = {
|
||||
from: this.from,
|
||||
to: email,
|
||||
subject: 'Reset Your Password - IMK Platform',
|
||||
subject: "Reset Your Password - IMK Platform",
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2>Password Reset Request</h2>
|
||||
@ -252,12 +256,12 @@ export class EmailService {
|
||||
};
|
||||
|
||||
try {
|
||||
this.logger.debug('Attempting to send password reset email...');
|
||||
this.logger.debug("Attempting to send password reset email...");
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
this.logger.log('Password reset email sent successfully:', info.response);
|
||||
this.logger.log("Password reset email sent successfully:", info.response);
|
||||
return info;
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to send password reset email:', {
|
||||
this.logger.error("Failed to send password reset email:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -268,12 +272,12 @@ export class EmailService {
|
||||
}
|
||||
|
||||
async sendPasswordChangeConfirmation(email: string, name: string) {
|
||||
this.logger.log('Sending password change confirmation to:', email);
|
||||
this.logger.log("Sending password change confirmation to:", email);
|
||||
|
||||
const mailOptions = {
|
||||
from: this.from,
|
||||
to: email,
|
||||
subject: 'Password Changed Successfully - IMK Platform',
|
||||
subject: "Password Changed Successfully - IMK Platform",
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2>Password Changed Successfully</h2>
|
||||
@ -286,12 +290,15 @@ export class EmailService {
|
||||
};
|
||||
|
||||
try {
|
||||
this.logger.debug('Attempting to send password change confirmation...');
|
||||
this.logger.debug("Attempting to send password change confirmation...");
|
||||
const info = await this.transporter.sendMail(mailOptions);
|
||||
this.logger.log('Password change confirmation sent successfully:', info.response);
|
||||
this.logger.log(
|
||||
"Password change confirmation sent successfully:",
|
||||
info.response,
|
||||
);
|
||||
return info;
|
||||
} catch (error) {
|
||||
this.logger.error('Failed to send password change confirmation:', {
|
||||
this.logger.error("Failed to send password change confirmation:", {
|
||||
error: error.message,
|
||||
code: error.code,
|
||||
command: error.command,
|
||||
@ -300,4 +307,4 @@ export class EmailService {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
backend/src/init/init.controller.spec.ts
Normal file
18
backend/src/init/init.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { InitController } from './init.controller';
|
||||
|
||||
describe('InitController', () => {
|
||||
let controller: InitController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [InitController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<InitController>(InitController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
15
backend/src/init/init.controller.ts
Normal file
15
backend/src/init/init.controller.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Controller, Post, Logger } from "@nestjs/common";
|
||||
import { InitService } from "./init.service";
|
||||
|
||||
@Controller("init")
|
||||
export class InitController {
|
||||
private readonly logger = new Logger(InitController.name);
|
||||
|
||||
constructor(private readonly initService: InitService) {}
|
||||
|
||||
@Post("system")
|
||||
async initializeSystem() {
|
||||
this.logger.log("Received system initialization request");
|
||||
return this.initService.initializeSystem();
|
||||
}
|
||||
}
|
||||
12
backend/src/init/init.module.ts
Normal file
12
backend/src/init/init.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { InitController } from "./init.controller";
|
||||
import { PrismaModule } from "../prisma/prisma.module";
|
||||
import { ConfigModule } from "@nestjs/config";
|
||||
import { InitService } from "./init.service";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, ConfigModule],
|
||||
providers: [InitService],
|
||||
controllers: [InitController],
|
||||
})
|
||||
export class InitModule {}
|
||||
18
backend/src/init/init.service.spec.ts
Normal file
18
backend/src/init/init.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { InitService } from './init.service';
|
||||
|
||||
describe('InitService', () => {
|
||||
let service: InitService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [InitService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<InitService>(InitService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
71
backend/src/init/init.service.ts
Normal file
71
backend/src/init/init.service.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
@Injectable()
|
||||
export class InitService {
|
||||
private readonly logger = new Logger(InitService.name);
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
async initializeSystem() {
|
||||
this.logger.log("Starting system initialization...");
|
||||
|
||||
const defaultAdminEmail =
|
||||
this.configService.get("DEFAULT_ADMIN_EMAIL") || "taratur@gmail";
|
||||
const defaultAdminPassword =
|
||||
this.configService.get("DEFAULT_ADMIN_PASSWORD") || "irina7654321";
|
||||
const defaultAdminName =
|
||||
this.configService.get("DEFAULT_ADMIN_NAME") || "System Admin";
|
||||
|
||||
try {
|
||||
// Check if admin already exists
|
||||
const existingAdmin = await this.prisma.user.findUnique({
|
||||
where: { email: defaultAdminEmail },
|
||||
});
|
||||
|
||||
if (!existingAdmin) {
|
||||
// Hash the password
|
||||
const hashedPassword = await bcrypt.hash(defaultAdminPassword, 10);
|
||||
|
||||
// Create the admin user
|
||||
const admin = await this.prisma.user.create({
|
||||
data: {
|
||||
email: defaultAdminEmail,
|
||||
name: defaultAdminName,
|
||||
password: hashedPassword,
|
||||
isAdmin: true,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.log("Default admin user created successfully");
|
||||
return {
|
||||
success: true,
|
||||
message: "System initialized successfully",
|
||||
admin: {
|
||||
id: admin.id,
|
||||
email: admin.email,
|
||||
name: admin.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "System already initialized",
|
||||
admin: {
|
||||
id: existingAdmin.id,
|
||||
email: existingAdmin.email,
|
||||
name: existingAdmin.name,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
this.logger.error("Error during system initialization:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user