create-backlist 7.3.1 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +901 -471
- package/bin/qa.js +191 -0
- package/package.json +27 -18
- package/src/ai-agent.js +581 -124
- package/src/analyzer.js +628 -528
- package/src/env-resolver.js +70 -70
- package/src/generators/dotnet.js +134 -134
- package/src/generators/java.js +248 -248
- package/src/generators/js.js +345 -345
- package/src/generators/nestjs.js +277 -277
- package/src/generators/python.js +86 -86
- package/src/project-detector.js +131 -131
- package/src/qa/qa-engine.js +1187 -0
- package/src/templates/dotnet/partials/Dockerfile.ejs +27 -27
- package/src/templates/dotnet/partials/docker-compose.yml.ejs +33 -33
- package/src/templates/js-express/base/server.js +59 -59
- package/src/templates/js-express/partials/Dockerfile.ejs +12 -12
- package/src/templates/js-express/partials/auth.controller.js.ejs +66 -66
- package/src/templates/js-express/partials/auth.middleware.js.ejs +19 -19
- package/src/templates/js-express/partials/auth.routes.js.ejs +9 -9
- package/src/templates/js-express/partials/controller.js.ejs +53 -53
- package/src/templates/js-express/partials/db.js.ejs +19 -19
- package/src/templates/js-express/partials/docker-compose.yml.ejs +46 -46
- package/src/templates/js-express/partials/model.js.ejs +18 -18
- package/src/templates/js-express/partials/package.json.ejs +17 -17
- package/src/templates/js-express/partials/prisma.schema.ejs +21 -21
- package/src/templates/js-express/partials/routes.js.ejs +19 -19
- package/src/templates/js-express/partials/seeder.js.ejs +103 -103
- package/src/templates/js-express/partials/service.js.ejs +51 -51
- package/src/templates/js-express/partials/swagger.js.ejs +30 -30
- package/src/templates/js-express/partials/test.js.ejs +46 -46
- package/src/templates/nestjs/base/app.module.ts +9 -9
- package/src/templates/nestjs/base/main.ts +23 -23
- package/src/templates/nestjs/base/tsconfig.json +21 -21
- package/src/templates/nestjs/partials/auth.controller.ts.ejs +17 -17
- package/src/templates/nestjs/partials/auth.module.ts.ejs +17 -17
- package/src/templates/nestjs/partials/auth.service.ts.ejs +70 -70
- package/src/templates/nestjs/partials/controller.ts.ejs +34 -34
- package/src/templates/nestjs/partials/create-dto.ts.ejs +22 -22
- package/src/templates/nestjs/partials/jwt-guard.ts.ejs +24 -24
- package/src/templates/nestjs/partials/module.ts.ejs +10 -10
- package/src/templates/nestjs/partials/package.json.ejs +27 -27
- package/src/templates/nestjs/partials/prisma.service.ts.ejs +13 -13
- package/src/templates/nestjs/partials/schema.ts.ejs +19 -19
- package/src/templates/nestjs/partials/service.ts.ejs +67 -67
- package/src/templates/nestjs/partials/update-dto.ts.ejs +4 -4
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import request from 'supertest';
|
|
3
|
-
|
|
4
|
-
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
|
|
5
|
-
|
|
6
|
-
describe('API Health Check', () => {
|
|
7
|
-
it('GET /api/health should return 200', async () => {
|
|
8
|
-
const res = await request(BASE_URL).get('/api/health');
|
|
9
|
-
expect(res.status).toBe(200);
|
|
10
|
-
expect(res.body.status).toBe('ok');
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
<% if (addAuth) { %>
|
|
15
|
-
describe('Auth Endpoints', () => {
|
|
16
|
-
const testUser = {
|
|
17
|
-
name: 'Test User',
|
|
18
|
-
email: `test_${Date.now()}@example.com`,
|
|
19
|
-
password: 'TestPass123!',
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
it('POST /api/auth/register should create a user', async () => {
|
|
23
|
-
const res = await request(BASE_URL).post('/api/auth/register').send(testUser);
|
|
24
|
-
expect(res.status).toBe(201);
|
|
25
|
-
expect(res.body).toHaveProperty('token');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('POST /api/auth/login should return a token', async () => {
|
|
29
|
-
const res = await request(BASE_URL).post('/api/auth/login').send({
|
|
30
|
-
email: testUser.email,
|
|
31
|
-
password: testUser.password,
|
|
32
|
-
});
|
|
33
|
-
expect(res.status).toBe(200);
|
|
34
|
-
expect(res.body).toHaveProperty('token');
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
<% } %>
|
|
38
|
-
|
|
39
|
-
<% endpoints.forEach(ep => { %>
|
|
40
|
-
describe('<%= ep.method.toUpperCase() %> <%= ep.path %>', () => {
|
|
41
|
-
it('should respond without 500', async () => {
|
|
42
|
-
const res = await request(BASE_URL).<%= ep.method.toLowerCase() %>('<%= ep.path %>');
|
|
43
|
-
expect(res.status).not.toBe(500);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
<% }); %>
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import request from 'supertest';
|
|
3
|
+
|
|
4
|
+
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
|
|
5
|
+
|
|
6
|
+
describe('API Health Check', () => {
|
|
7
|
+
it('GET /api/health should return 200', async () => {
|
|
8
|
+
const res = await request(BASE_URL).get('/api/health');
|
|
9
|
+
expect(res.status).toBe(200);
|
|
10
|
+
expect(res.body.status).toBe('ok');
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
<% if (addAuth) { %>
|
|
15
|
+
describe('Auth Endpoints', () => {
|
|
16
|
+
const testUser = {
|
|
17
|
+
name: 'Test User',
|
|
18
|
+
email: `test_${Date.now()}@example.com`,
|
|
19
|
+
password: 'TestPass123!',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
it('POST /api/auth/register should create a user', async () => {
|
|
23
|
+
const res = await request(BASE_URL).post('/api/auth/register').send(testUser);
|
|
24
|
+
expect(res.status).toBe(201);
|
|
25
|
+
expect(res.body).toHaveProperty('token');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('POST /api/auth/login should return a token', async () => {
|
|
29
|
+
const res = await request(BASE_URL).post('/api/auth/login').send({
|
|
30
|
+
email: testUser.email,
|
|
31
|
+
password: testUser.password,
|
|
32
|
+
});
|
|
33
|
+
expect(res.status).toBe(200);
|
|
34
|
+
expect(res.body).toHaveProperty('token');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
<% } %>
|
|
38
|
+
|
|
39
|
+
<% endpoints.forEach(ep => { %>
|
|
40
|
+
describe('<%= ep.method.toUpperCase() %> <%= ep.path %>', () => {
|
|
41
|
+
it('should respond without 500', async () => {
|
|
42
|
+
const res = await request(BASE_URL).<%= ep.method.toLowerCase() %>('<%= ep.path %>');
|
|
43
|
+
expect(res.status).not.toBe(500);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
<% }); %>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
// INJECT:IMPORTS
|
|
3
|
-
|
|
4
|
-
@Module({
|
|
5
|
-
imports: [
|
|
6
|
-
// INJECT:MODULES
|
|
7
|
-
],
|
|
8
|
-
})
|
|
9
|
-
export class AppModule {}
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
// INJECT:IMPORTS
|
|
3
|
+
|
|
4
|
+
@Module({
|
|
5
|
+
imports: [
|
|
6
|
+
// INJECT:MODULES
|
|
7
|
+
],
|
|
8
|
+
})
|
|
9
|
+
export class AppModule {}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import { NestFactory } from '@nestjs/core';
|
|
2
|
-
import { ValidationPipe } from '@nestjs/common';
|
|
3
|
-
import { AppModule } from './app.module';
|
|
4
|
-
|
|
5
|
-
async function bootstrap() {
|
|
6
|
-
const app = await NestFactory.create(AppModule);
|
|
7
|
-
|
|
8
|
-
app.enableCors({
|
|
9
|
-
origin: process.env.CORS_ORIGIN
|
|
10
|
-
? process.env.CORS_ORIGIN.split(',').map(s => s.trim())
|
|
11
|
-
: ['http://localhost:3000', 'http://localhost:5173'],
|
|
12
|
-
credentials: true,
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
app.setGlobalPrefix('api');
|
|
16
|
-
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
|
|
17
|
-
|
|
18
|
-
const port = process.env.PORT || 8000;
|
|
19
|
-
await app.listen(port);
|
|
20
|
-
console.log(`NestJS server running on http://localhost:${port}`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
bootstrap();
|
|
1
|
+
import { NestFactory } from '@nestjs/core';
|
|
2
|
+
import { ValidationPipe } from '@nestjs/common';
|
|
3
|
+
import { AppModule } from './app.module';
|
|
4
|
+
|
|
5
|
+
async function bootstrap() {
|
|
6
|
+
const app = await NestFactory.create(AppModule);
|
|
7
|
+
|
|
8
|
+
app.enableCors({
|
|
9
|
+
origin: process.env.CORS_ORIGIN
|
|
10
|
+
? process.env.CORS_ORIGIN.split(',').map(s => s.trim())
|
|
11
|
+
: ['http://localhost:3000', 'http://localhost:5173'],
|
|
12
|
+
credentials: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
app.setGlobalPrefix('api');
|
|
16
|
+
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
|
|
17
|
+
|
|
18
|
+
const port = process.env.PORT || 8000;
|
|
19
|
+
await app.listen(port);
|
|
20
|
+
console.log(`NestJS server running on http://localhost:${port}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
bootstrap();
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"module": "commonjs",
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"removeComments": true,
|
|
6
|
-
"emitDecoratorMetadata": true,
|
|
7
|
-
"experimentalDecorators": true,
|
|
8
|
-
"allowSyntheticDefaultImports": true,
|
|
9
|
-
"target": "ES2021",
|
|
10
|
-
"sourceMap": true,
|
|
11
|
-
"outDir": "./dist",
|
|
12
|
-
"baseUrl": "./",
|
|
13
|
-
"incremental": true,
|
|
14
|
-
"skipLibCheck": true,
|
|
15
|
-
"strictNullChecks": true,
|
|
16
|
-
"noImplicitAny": true,
|
|
17
|
-
"strictBindCallApply": true,
|
|
18
|
-
"forceConsistentCasingInFileNames": true,
|
|
19
|
-
"noFallthroughCasesInSwitch": true
|
|
20
|
-
}
|
|
21
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"module": "commonjs",
|
|
4
|
+
"declaration": true,
|
|
5
|
+
"removeComments": true,
|
|
6
|
+
"emitDecoratorMetadata": true,
|
|
7
|
+
"experimentalDecorators": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"target": "ES2021",
|
|
10
|
+
"sourceMap": true,
|
|
11
|
+
"outDir": "./dist",
|
|
12
|
+
"baseUrl": "./",
|
|
13
|
+
"incremental": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"strictNullChecks": true,
|
|
16
|
+
"noImplicitAny": true,
|
|
17
|
+
"strictBindCallApply": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Controller, Post, Body } from '@nestjs/common';
|
|
2
|
-
import { AuthService } from './auth.service';
|
|
3
|
-
|
|
4
|
-
@Controller('auth')
|
|
5
|
-
export class AuthController {
|
|
6
|
-
constructor(private readonly authService: AuthService) {}
|
|
7
|
-
|
|
8
|
-
@Post('register')
|
|
9
|
-
register(@Body() body: { name: string; email: string; password: string }) {
|
|
10
|
-
return this.authService.register(body.name, body.email, body.password);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
@Post('login')
|
|
14
|
-
login(@Body() body: { email: string; password: string }) {
|
|
15
|
-
return this.authService.login(body.email, body.password);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
1
|
+
import { Controller, Post, Body } from '@nestjs/common';
|
|
2
|
+
import { AuthService } from './auth.service';
|
|
3
|
+
|
|
4
|
+
@Controller('auth')
|
|
5
|
+
export class AuthController {
|
|
6
|
+
constructor(private readonly authService: AuthService) {}
|
|
7
|
+
|
|
8
|
+
@Post('register')
|
|
9
|
+
register(@Body() body: { name: string; email: string; password: string }) {
|
|
10
|
+
return this.authService.register(body.name, body.email, body.password);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@Post('login')
|
|
14
|
+
login(@Body() body: { email: string; password: string }) {
|
|
15
|
+
return this.authService.login(body.email, body.password);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { JwtModule } from '@nestjs/jwt';
|
|
3
|
-
import { AuthController } from './auth.controller';
|
|
4
|
-
import { AuthService } from './auth.service';
|
|
5
|
-
|
|
6
|
-
@Module({
|
|
7
|
-
imports: [
|
|
8
|
-
JwtModule.register({
|
|
9
|
-
secret: process.env.JWT_SECRET || 'changeme',
|
|
10
|
-
signOptions: { expiresIn: process.env.JWT_EXPIRES_IN || '5h' },
|
|
11
|
-
}),
|
|
12
|
-
],
|
|
13
|
-
controllers: [AuthController],
|
|
14
|
-
providers: [AuthService],
|
|
15
|
-
exports: [AuthService, JwtModule],
|
|
16
|
-
})
|
|
17
|
-
export class AuthModule {}
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { JwtModule } from '@nestjs/jwt';
|
|
3
|
+
import { AuthController } from './auth.controller';
|
|
4
|
+
import { AuthService } from './auth.service';
|
|
5
|
+
|
|
6
|
+
@Module({
|
|
7
|
+
imports: [
|
|
8
|
+
JwtModule.register({
|
|
9
|
+
secret: process.env.JWT_SECRET || 'changeme',
|
|
10
|
+
signOptions: { expiresIn: process.env.JWT_EXPIRES_IN || '5h' },
|
|
11
|
+
}),
|
|
12
|
+
],
|
|
13
|
+
controllers: [AuthController],
|
|
14
|
+
providers: [AuthService],
|
|
15
|
+
exports: [AuthService, JwtModule],
|
|
16
|
+
})
|
|
17
|
+
export class AuthModule {}
|
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
<% if (dbType === 'mongoose') { %>
|
|
2
|
-
import { Injectable, ConflictException, UnauthorizedException } from '@nestjs/common';
|
|
3
|
-
import { JwtService } from '@nestjs/jwt';
|
|
4
|
-
import { InjectModel } from '@nestjs/mongoose';
|
|
5
|
-
import { Model } from 'mongoose';
|
|
6
|
-
import * as bcrypt from 'bcryptjs';
|
|
7
|
-
|
|
8
|
-
@Injectable()
|
|
9
|
-
export class AuthService {
|
|
10
|
-
constructor(
|
|
11
|
-
@InjectModel('User') private readonly userModel: Model<any>,
|
|
12
|
-
private readonly jwtService: JwtService,
|
|
13
|
-
) {}
|
|
14
|
-
|
|
15
|
-
async register(name: string, email: string, password: string) {
|
|
16
|
-
const existing = await this.userModel.findOne({ email });
|
|
17
|
-
if (existing) throw new ConflictException('Email already in use');
|
|
18
|
-
|
|
19
|
-
const hashed = await bcrypt.hash(password, 12);
|
|
20
|
-
const user = await this.userModel.create({ name, email, password: hashed });
|
|
21
|
-
const token = this.jwtService.sign({ id: user._id, email: user.email });
|
|
22
|
-
return { token, user: { id: user._id, name: user.name, email: user.email } };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
async login(email: string, password: string) {
|
|
26
|
-
const user = await this.userModel.findOne({ email });
|
|
27
|
-
if (!user) throw new UnauthorizedException('Invalid credentials');
|
|
28
|
-
|
|
29
|
-
const isMatch = await bcrypt.compare(password, user.password);
|
|
30
|
-
if (!isMatch) throw new UnauthorizedException('Invalid credentials');
|
|
31
|
-
|
|
32
|
-
const token = this.jwtService.sign({ id: user._id, email: user.email });
|
|
33
|
-
return { token, user: { id: user._id, name: user.name, email: user.email } };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
<% } else { %>
|
|
37
|
-
import { Injectable, ConflictException, UnauthorizedException } from '@nestjs/common';
|
|
38
|
-
import { JwtService } from '@nestjs/jwt';
|
|
39
|
-
import { PrismaService } from '../prisma/prisma.service';
|
|
40
|
-
import * as bcrypt from 'bcryptjs';
|
|
41
|
-
|
|
42
|
-
@Injectable()
|
|
43
|
-
export class AuthService {
|
|
44
|
-
constructor(
|
|
45
|
-
private readonly prisma: PrismaService,
|
|
46
|
-
private readonly jwtService: JwtService,
|
|
47
|
-
) {}
|
|
48
|
-
|
|
49
|
-
async register(name: string, email: string, password: string) {
|
|
50
|
-
const existing = await this.prisma.user.findUnique({ where: { email } });
|
|
51
|
-
if (existing) throw new ConflictException('Email already in use');
|
|
52
|
-
|
|
53
|
-
const hashed = await bcrypt.hash(password, 12);
|
|
54
|
-
const user = await this.prisma.user.create({ data: { name, email, password: hashed } });
|
|
55
|
-
const token = this.jwtService.sign({ id: user.id, email: user.email });
|
|
56
|
-
return { token, user: { id: user.id, name: user.name, email: user.email } };
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async login(email: string, password: string) {
|
|
60
|
-
const user = await this.prisma.user.findUnique({ where: { email } });
|
|
61
|
-
if (!user) throw new UnauthorizedException('Invalid credentials');
|
|
62
|
-
|
|
63
|
-
const isMatch = await bcrypt.compare(password, user.password);
|
|
64
|
-
if (!isMatch) throw new UnauthorizedException('Invalid credentials');
|
|
65
|
-
|
|
66
|
-
const token = this.jwtService.sign({ id: user.id, email: user.email });
|
|
67
|
-
return { token, user: { id: user.id, name: user.name, email: user.email } };
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
<% } %>
|
|
1
|
+
<% if (dbType === 'mongoose') { %>
|
|
2
|
+
import { Injectable, ConflictException, UnauthorizedException } from '@nestjs/common';
|
|
3
|
+
import { JwtService } from '@nestjs/jwt';
|
|
4
|
+
import { InjectModel } from '@nestjs/mongoose';
|
|
5
|
+
import { Model } from 'mongoose';
|
|
6
|
+
import * as bcrypt from 'bcryptjs';
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class AuthService {
|
|
10
|
+
constructor(
|
|
11
|
+
@InjectModel('User') private readonly userModel: Model<any>,
|
|
12
|
+
private readonly jwtService: JwtService,
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async register(name: string, email: string, password: string) {
|
|
16
|
+
const existing = await this.userModel.findOne({ email });
|
|
17
|
+
if (existing) throw new ConflictException('Email already in use');
|
|
18
|
+
|
|
19
|
+
const hashed = await bcrypt.hash(password, 12);
|
|
20
|
+
const user = await this.userModel.create({ name, email, password: hashed });
|
|
21
|
+
const token = this.jwtService.sign({ id: user._id, email: user.email });
|
|
22
|
+
return { token, user: { id: user._id, name: user.name, email: user.email } };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async login(email: string, password: string) {
|
|
26
|
+
const user = await this.userModel.findOne({ email });
|
|
27
|
+
if (!user) throw new UnauthorizedException('Invalid credentials');
|
|
28
|
+
|
|
29
|
+
const isMatch = await bcrypt.compare(password, user.password);
|
|
30
|
+
if (!isMatch) throw new UnauthorizedException('Invalid credentials');
|
|
31
|
+
|
|
32
|
+
const token = this.jwtService.sign({ id: user._id, email: user.email });
|
|
33
|
+
return { token, user: { id: user._id, name: user.name, email: user.email } };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
<% } else { %>
|
|
37
|
+
import { Injectable, ConflictException, UnauthorizedException } from '@nestjs/common';
|
|
38
|
+
import { JwtService } from '@nestjs/jwt';
|
|
39
|
+
import { PrismaService } from '../prisma/prisma.service';
|
|
40
|
+
import * as bcrypt from 'bcryptjs';
|
|
41
|
+
|
|
42
|
+
@Injectable()
|
|
43
|
+
export class AuthService {
|
|
44
|
+
constructor(
|
|
45
|
+
private readonly prisma: PrismaService,
|
|
46
|
+
private readonly jwtService: JwtService,
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
async register(name: string, email: string, password: string) {
|
|
50
|
+
const existing = await this.prisma.user.findUnique({ where: { email } });
|
|
51
|
+
if (existing) throw new ConflictException('Email already in use');
|
|
52
|
+
|
|
53
|
+
const hashed = await bcrypt.hash(password, 12);
|
|
54
|
+
const user = await this.prisma.user.create({ data: { name, email, password: hashed } });
|
|
55
|
+
const token = this.jwtService.sign({ id: user.id, email: user.email });
|
|
56
|
+
return { token, user: { id: user.id, name: user.name, email: user.email } };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async login(email: string, password: string) {
|
|
60
|
+
const user = await this.prisma.user.findUnique({ where: { email } });
|
|
61
|
+
if (!user) throw new UnauthorizedException('Invalid credentials');
|
|
62
|
+
|
|
63
|
+
const isMatch = await bcrypt.compare(password, user.password);
|
|
64
|
+
if (!isMatch) throw new UnauthorizedException('Invalid credentials');
|
|
65
|
+
|
|
66
|
+
const token = this.jwtService.sign({ id: user.id, email: user.email });
|
|
67
|
+
return { token, user: { id: user.id, name: user.name, email: user.email } };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
<% } %>
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
|
|
2
|
-
import { <%= modelName %>Service } from './<%= modelName.toLowerCase() %>.service';
|
|
3
|
-
import { Create<%= modelName %>Dto } from './dto/create-<%= modelName.toLowerCase() %>.dto';
|
|
4
|
-
import { Update<%= modelName %>Dto } from './dto/update-<%= modelName.toLowerCase() %>.dto';
|
|
5
|
-
|
|
6
|
-
@Controller('<%= modelName.toLowerCase() %>s')
|
|
7
|
-
export class <%= modelName %>Controller {
|
|
8
|
-
constructor(private readonly <%= modelName.toLowerCase() %>Service: <%= modelName %>Service) {}
|
|
9
|
-
|
|
10
|
-
@Get()
|
|
11
|
-
findAll() {
|
|
12
|
-
return this.<%= modelName.toLowerCase() %>Service.findAll();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
@Get(':id')
|
|
16
|
-
findOne(@Param('id') id: string) {
|
|
17
|
-
return this.<%= modelName.toLowerCase() %>Service.findOne(id);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@Post()
|
|
21
|
-
create(@Body() dto: Create<%= modelName %>Dto) {
|
|
22
|
-
return this.<%= modelName.toLowerCase() %>Service.create(dto);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@Put(':id')
|
|
26
|
-
update(@Param('id') id: string, @Body() dto: Update<%= modelName %>Dto) {
|
|
27
|
-
return this.<%= modelName.toLowerCase() %>Service.update(id, dto);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
@Delete(':id')
|
|
31
|
-
remove(@Param('id') id: string) {
|
|
32
|
-
return this.<%= modelName.toLowerCase() %>Service.remove(id);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
1
|
+
import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common';
|
|
2
|
+
import { <%= modelName %>Service } from './<%= modelName.toLowerCase() %>.service';
|
|
3
|
+
import { Create<%= modelName %>Dto } from './dto/create-<%= modelName.toLowerCase() %>.dto';
|
|
4
|
+
import { Update<%= modelName %>Dto } from './dto/update-<%= modelName.toLowerCase() %>.dto';
|
|
5
|
+
|
|
6
|
+
@Controller('<%= modelName.toLowerCase() %>s')
|
|
7
|
+
export class <%= modelName %>Controller {
|
|
8
|
+
constructor(private readonly <%= modelName.toLowerCase() %>Service: <%= modelName %>Service) {}
|
|
9
|
+
|
|
10
|
+
@Get()
|
|
11
|
+
findAll() {
|
|
12
|
+
return this.<%= modelName.toLowerCase() %>Service.findAll();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Get(':id')
|
|
16
|
+
findOne(@Param('id') id: string) {
|
|
17
|
+
return this.<%= modelName.toLowerCase() %>Service.findOne(id);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Post()
|
|
21
|
+
create(@Body() dto: Create<%= modelName %>Dto) {
|
|
22
|
+
return this.<%= modelName.toLowerCase() %>Service.create(dto);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Put(':id')
|
|
26
|
+
update(@Param('id') id: string, @Body() dto: Update<%= modelName %>Dto) {
|
|
27
|
+
return this.<%= modelName.toLowerCase() %>Service.update(id, dto);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Delete(':id')
|
|
31
|
+
remove(@Param('id') id: string) {
|
|
32
|
+
return this.<%= modelName.toLowerCase() %>Service.remove(id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { IsString, IsOptional, IsNotEmpty } from 'class-validator';
|
|
2
|
-
|
|
3
|
-
export class Create<%= modelName %>Dto {
|
|
4
|
-
<% fields.forEach(field => { %>
|
|
5
|
-
<% if (field.name === 'password' || field.name === 'email' || field.name === 'name') { %>
|
|
6
|
-
@IsString()
|
|
7
|
-
@IsNotEmpty()
|
|
8
|
-
<%= field.name %>: string;
|
|
9
|
-
<% } else if (field.type === 'Number' || field.type === 'Int') { %>
|
|
10
|
-
@IsOptional()
|
|
11
|
-
<%= field.name %>?: number;
|
|
12
|
-
<% } else if (field.type === 'Boolean') { %>
|
|
13
|
-
@IsOptional()
|
|
14
|
-
<%= field.name %>?: boolean;
|
|
15
|
-
<% } else { %>
|
|
16
|
-
@IsOptional()
|
|
17
|
-
@IsString()
|
|
18
|
-
<%= field.name %>?: string;
|
|
19
|
-
<% } %>
|
|
20
|
-
|
|
21
|
-
<% }); %>
|
|
22
|
-
}
|
|
1
|
+
import { IsString, IsOptional, IsNotEmpty } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
export class Create<%= modelName %>Dto {
|
|
4
|
+
<% fields.forEach(field => { %>
|
|
5
|
+
<% if (field.name === 'password' || field.name === 'email' || field.name === 'name') { %>
|
|
6
|
+
@IsString()
|
|
7
|
+
@IsNotEmpty()
|
|
8
|
+
<%= field.name %>: string;
|
|
9
|
+
<% } else if (field.type === 'Number' || field.type === 'Int') { %>
|
|
10
|
+
@IsOptional()
|
|
11
|
+
<%= field.name %>?: number;
|
|
12
|
+
<% } else if (field.type === 'Boolean') { %>
|
|
13
|
+
@IsOptional()
|
|
14
|
+
<%= field.name %>?: boolean;
|
|
15
|
+
<% } else { %>
|
|
16
|
+
@IsOptional()
|
|
17
|
+
@IsString()
|
|
18
|
+
<%= field.name %>?: string;
|
|
19
|
+
<% } %>
|
|
20
|
+
|
|
21
|
+
<% }); %>
|
|
22
|
+
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
|
2
|
-
import { JwtService } from '@nestjs/jwt';
|
|
3
|
-
|
|
4
|
-
@Injectable()
|
|
5
|
-
export class JwtAuthGuard implements CanActivate {
|
|
6
|
-
constructor(private readonly jwtService: JwtService) {}
|
|
7
|
-
|
|
8
|
-
canActivate(context: ExecutionContext): boolean {
|
|
9
|
-
const request = context.switchToHttp().getRequest();
|
|
10
|
-
const authHeader = request.headers.authorization;
|
|
11
|
-
|
|
12
|
-
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
13
|
-
throw new UnauthorizedException('Access denied. No token provided.');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const token = authHeader.split(' ')[1];
|
|
17
|
-
try {
|
|
18
|
-
request.user = this.jwtService.verify(token);
|
|
19
|
-
return true;
|
|
20
|
-
} catch {
|
|
21
|
-
throw new UnauthorizedException('Invalid or expired token.');
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
1
|
+
import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
|
|
2
|
+
import { JwtService } from '@nestjs/jwt';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
5
|
+
export class JwtAuthGuard implements CanActivate {
|
|
6
|
+
constructor(private readonly jwtService: JwtService) {}
|
|
7
|
+
|
|
8
|
+
canActivate(context: ExecutionContext): boolean {
|
|
9
|
+
const request = context.switchToHttp().getRequest();
|
|
10
|
+
const authHeader = request.headers.authorization;
|
|
11
|
+
|
|
12
|
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
|
13
|
+
throw new UnauthorizedException('Access denied. No token provided.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const token = authHeader.split(' ')[1];
|
|
17
|
+
try {
|
|
18
|
+
request.user = this.jwtService.verify(token);
|
|
19
|
+
return true;
|
|
20
|
+
} catch {
|
|
21
|
+
throw new UnauthorizedException('Invalid or expired token.');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { <%= modelName %>Controller } from './<%= modelName.toLowerCase() %>.controller';
|
|
3
|
-
import { <%= modelName %>Service } from './<%= modelName.toLowerCase() %>.service';
|
|
4
|
-
|
|
5
|
-
@Module({
|
|
6
|
-
controllers: [<%= modelName %>Controller],
|
|
7
|
-
providers: [<%= modelName %>Service],
|
|
8
|
-
exports: [<%= modelName %>Service],
|
|
9
|
-
})
|
|
10
|
-
export class <%= modelName %>Module {}
|
|
1
|
+
import { Module } from '@nestjs/common';
|
|
2
|
+
import { <%= modelName %>Controller } from './<%= modelName.toLowerCase() %>.controller';
|
|
3
|
+
import { <%= modelName %>Service } from './<%= modelName.toLowerCase() %>.service';
|
|
4
|
+
|
|
5
|
+
@Module({
|
|
6
|
+
controllers: [<%= modelName %>Controller],
|
|
7
|
+
providers: [<%= modelName %>Service],
|
|
8
|
+
exports: [<%= modelName %>Service],
|
|
9
|
+
})
|
|
10
|
+
export class <%= modelName %>Module {}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
<%= JSON.stringify({
|
|
2
|
-
name: projectName,
|
|
3
|
-
version: "1.0.0",
|
|
4
|
-
scripts: {
|
|
5
|
-
build: "nest build",
|
|
6
|
-
start: "nest start",
|
|
7
|
-
"start:dev": "nest start --watch",
|
|
8
|
-
"start:prod": "node dist/main"
|
|
9
|
-
},
|
|
10
|
-
dependencies: {
|
|
11
|
-
"@nestjs/common": "^10.3.0",
|
|
12
|
-
"@nestjs/core": "^10.3.0",
|
|
13
|
-
"@nestjs/platform-express": "^10.3.0",
|
|
14
|
-
"class-transformer": "^0.5.1",
|
|
15
|
-
"class-validator": "^0.14.0",
|
|
16
|
-
"reflect-metadata": "^0.1.14",
|
|
17
|
-
rxjs: "^7.8.1"
|
|
18
|
-
},
|
|
19
|
-
devDependencies: {
|
|
20
|
-
"@nestjs/cli": "^10.3.0",
|
|
21
|
-
"@nestjs/schematics": "^10.1.0",
|
|
22
|
-
"@types/express": "^4.17.21",
|
|
23
|
-
"@types/node": "^20.10.0",
|
|
24
|
-
"ts-node": "^10.9.2",
|
|
25
|
-
typescript: "^5.3.2"
|
|
26
|
-
}
|
|
27
|
-
}, null, 2) %>
|
|
1
|
+
<%= JSON.stringify({
|
|
2
|
+
name: projectName,
|
|
3
|
+
version: "1.0.0",
|
|
4
|
+
scripts: {
|
|
5
|
+
build: "nest build",
|
|
6
|
+
start: "nest start",
|
|
7
|
+
"start:dev": "nest start --watch",
|
|
8
|
+
"start:prod": "node dist/main"
|
|
9
|
+
},
|
|
10
|
+
dependencies: {
|
|
11
|
+
"@nestjs/common": "^10.3.0",
|
|
12
|
+
"@nestjs/core": "^10.3.0",
|
|
13
|
+
"@nestjs/platform-express": "^10.3.0",
|
|
14
|
+
"class-transformer": "^0.5.1",
|
|
15
|
+
"class-validator": "^0.14.0",
|
|
16
|
+
"reflect-metadata": "^0.1.14",
|
|
17
|
+
rxjs: "^7.8.1"
|
|
18
|
+
},
|
|
19
|
+
devDependencies: {
|
|
20
|
+
"@nestjs/cli": "^10.3.0",
|
|
21
|
+
"@nestjs/schematics": "^10.1.0",
|
|
22
|
+
"@types/express": "^4.17.21",
|
|
23
|
+
"@types/node": "^20.10.0",
|
|
24
|
+
"ts-node": "^10.9.2",
|
|
25
|
+
typescript: "^5.3.2"
|
|
26
|
+
}
|
|
27
|
+
}, null, 2) %>
|