Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 50 additions & 48 deletions src/assets/assets.service.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,70 @@
import { Injectable, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../common/prisma.service';
import { CreateAssetDto } from './dto/create-asset.dto';
import { UpdateAssetDto } from './dto/update-asset.dto';
import {
AssetNotFoundException,
AssetAlreadyExistsException,
InvalidAssetDataException,
AssetServiceException
} from './exceptions/custom-exceptions';
import { Injectable, BadRequestException } from "@nestjs/common";
import { PrismaService } from "../common/prisma.service";
import { CreateAssetDto } from "./dto/create-asset.dto";
import { UpdateAssetDto } from "./dto/update-asset.dto";
import {
AssetNotFoundException,
AssetAlreadyExistsException,
AssetServiceException,
} from "./exceptions/custom-exceptions";

@Injectable()
export class AssetsService {
constructor(private prisma: PrismaService) {}

async create(createAssetDto: CreateAssetDto) {
try {

const existingAsset = await this.prisma.assets.findUnique({
where: { symbol: createAssetDto.symbol.toUpperCase() }
where: { symbol: createAssetDto.symbol.toUpperCase() },
});

if (existingAsset) {
throw new AssetAlreadyExistsException(createAssetDto.symbol);
}


const asset = await this.prisma.assets.create({
data: {
...createAssetDto,
symbol: createAssetDto.symbol.toUpperCase(),
}
},
});

return {
...asset,
price: parseFloat((asset as any).price.toString())
price: parseFloat((asset as any).price.toString()),
};
} catch (error) {
if (error instanceof AssetAlreadyExistsException) {
throw error;
}
throw new AssetServiceException('Failed to create asset', error);
throw new AssetServiceException("Failed to create asset", error);
}
}

async findAll() {
try {
const assets = await this.prisma.assets.findMany({
where: { isActive: true },
orderBy: { createdAt: 'desc' }
orderBy: { createdAt: "desc" },
});
return assets.map(asset => ({

return assets.map((asset) => ({
...asset,
price: parseFloat((asset as any).price.toString())
price: parseFloat((asset as any).price.toString()),
}));
} catch (error) {
throw new AssetServiceException('Failed to fetch assets', error);
throw new AssetServiceException("Failed to fetch assets", error);
}
}

async findOne(id: number) {
try {
if (!this.isValidId(id)) {
throw new BadRequestException('ID must be a positive number');
throw new BadRequestException("ID must be a positive number");
}

const asset = await this.prisma.assets.findUnique({
where: { id }
where: { id },
});

if (!asset) {
Expand All @@ -76,89 +73,94 @@ export class AssetsService {

return {
...asset,
price: parseFloat((asset as any).price.toString())
price: parseFloat((asset as any).price.toString()),
};
} catch (error) {
if (error instanceof AssetNotFoundException || error instanceof BadRequestException) {
if (
error instanceof AssetNotFoundException ||
error instanceof BadRequestException
) {
throw error;
}
throw new AssetServiceException('Failed to fetch asset', error);
throw new AssetServiceException("Failed to fetch asset", error);
}
}

async update(id: number, updateAssetDto: UpdateAssetDto) {
try {
if (!this.isValidId(id)) {
throw new BadRequestException('ID must be a positive number');
throw new BadRequestException("ID must be a positive number");
}

if (Object.keys(updateAssetDto).length === 0) {
throw new BadRequestException('At least one field must be provided for update');
throw new BadRequestException(
"At least one field must be provided for update"
);
}


await this.findOne(id);


if (updateAssetDto.symbol) {
const existingAsset = await this.prisma.assets.findFirst({
where: {
where: {
symbol: updateAssetDto.symbol.toUpperCase(),
id: { not: id }
}
id: { not: id },
},
});

if (existingAsset) {
throw new AssetAlreadyExistsException(updateAssetDto.symbol);
}
}


const asset = await this.prisma.assets.update({
where: { id },
data: {
...updateAssetDto,
symbol: updateAssetDto.symbol?.toUpperCase(),
}
},
});

return {
...asset,
price: parseFloat((asset as any).price.toString())
price: parseFloat((asset as any).price.toString()),
};
} catch (error) {
if (error instanceof AssetNotFoundException ||
error instanceof AssetAlreadyExistsException ||
error instanceof BadRequestException) {
if (
error instanceof AssetNotFoundException ||
error instanceof AssetAlreadyExistsException ||
error instanceof BadRequestException
) {
throw error;
}
throw new AssetServiceException('Failed to update asset', error);
throw new AssetServiceException("Failed to update asset", error);
}
}

async remove(id: number) {
try {
if (!this.isValidId(id)) {
throw new BadRequestException('ID must be a positive number');
throw new BadRequestException("ID must be a positive number");
}


await this.findOne(id);

await this.prisma.assets.update({
where: { id },
data: { isActive: false }
data: { isActive: false },
});
} catch (error) {
if (error instanceof AssetNotFoundException || error instanceof BadRequestException) {
if (
error instanceof AssetNotFoundException ||
error instanceof BadRequestException
) {
throw error;
}
throw new AssetServiceException('Failed to remove asset', error);
throw new AssetServiceException("Failed to remove asset", error);
}
}

private isValidId(id: number): boolean {
return Number.isInteger(id) && id > 0;
}

}
}
92 changes: 48 additions & 44 deletions src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Controller, Post, Body, Get, Res } from "@nestjs/common";
import { Controller, Post, Body, Get, Res, HttpCode } from "@nestjs/common";
import { type Response } from "express";
import {
ApiBadRequestResponse,
Expand All @@ -12,7 +12,7 @@ import {
import { AuthService } from "./auth.service";
import { LoginDto } from "./dto/login.dto";
import { Public } from "./decorators/public.decorator";
import { CurrentUser } from "./decorators/current-user.decorator";
// import { CurrentUser } from "./decorators/current-user.decorator";

@ApiTags("Auth")
@Controller("auth")
Expand All @@ -21,6 +21,7 @@ export class AuthController {

@Public()
@Post("login")
@HttpCode(200)
@ApiOperation({
summary: "Realiza login com email e senha",
description:
Expand All @@ -32,8 +33,8 @@ export class AuthController {
exemplo: {
summary: "Corpo do login",
value: {
email: "user@example.com",
password: "123456",
email: "admin@bolsa.com",
password: "admin123",
},
},
},
Expand All @@ -44,7 +45,7 @@ export class AuthController {
example: {
user: {
id: 1,
email: "user@example.com",
email: "admin@bolsa.com",
role: "user",
},
},
Expand All @@ -55,7 +56,10 @@ export class AuthController {
schema: {
example: {
statusCode: 400,
message: "Forneça um email válido",
message: [
"email must be an email",
"password must be longer than or equal to 3 characters",
],
error: "Bad Request",
},
},
Expand Down Expand Up @@ -91,42 +95,42 @@ export class AuthController {
return { user };
}

@Get("profile")
@ApiCookieAuth()
@ApiOperation({
summary: "Retorna dados do usuário autenticado",
description: "Endpoint protegido por JWT via cookie httpOnly.",
})
@ApiOkResponse({
description: "Retorna o usuário logado",
schema: {
example: {
message: "Dados do usuário autenticado",
user: {
id: 1,
email: "user@example.com",
role: "user",
},
},
},
})
@ApiUnauthorizedResponse({
description: "Token inválido ou ausente",
schema: {
example: {
statusCode: 401,
message: "Unauthorized",
},
},
})
async getProfile(@CurrentUser() user: any) {
return {
message: "Dados do usuário autenticado",
user: {
id: user.userId,
email: user.email,
role: user.role,
},
};
}
// @Get("profile")
// @ApiCookieAuth()
// @ApiOperation({
// summary: "Retorna dados do usuário autenticado",
// description: "Endpoint protegido por JWT via cookie httpOnly.",
// })
// @ApiOkResponse({
// description: "Retorna o usuário logado",
// schema: {
// example: {
// message: "Dados do usuário autenticado",
// user: {
// id: 1,
// email: "admin@bolsa.com",
// role: "user",
// },
// },
// },
// })
// @ApiUnauthorizedResponse({
// description: "Token inválido ou ausente",
// schema: {
// example: {
// statusCode: 401,
// message: "Unauthorized",
// },
// },
// })
// async getProfile(@CurrentUser() user: any) {
// return {
// message: "Dados do usuário autenticado",
// user: {
// id: user.userId,
// email: user.email,
// role: user.role,
// },
// };
// }
}
3 changes: 1 addition & 2 deletions src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { JwtService } from "@nestjs/jwt";
import { UsersService } from "../users/users.service";
import * as bcrypt from "bcryptjs";


@Injectable()
export class AuthService {
constructor(
Expand All @@ -28,7 +27,7 @@ export class AuthService {
const user = await this.validateUser(email, password);

if (!user) {
throw new UnauthorizedException("Credenciais inválidas");
throw new UnauthorizedException("Email ou senha incorretos");
}

const payload = {
Expand Down
Loading