├── .gitignore ├── src ├── jwt │ └── jwtPassword.ts ├── middlewares │ ├── auth │ │ ├── index.ts │ │ └── auth.ts │ ├── user │ │ ├── verifyUserBody.ts │ │ ├── verifyPassword.ts │ │ ├── verifyLoginUserBody.ts │ │ ├── verifyUpdateUserBody.ts │ │ ├── verifyUpdatePhoneUser.ts │ │ ├── verifyUpdateEmailUserBody.ts │ │ ├── verifyUpdatePasswordUserBody.ts │ │ ├── verifyCardBody.ts │ │ ├── verifyUpdateCardPassword.ts │ │ └── index.ts │ ├── transaction │ │ ├── verifyPixValue.ts │ │ ├── verifyCardPay.ts │ │ ├── verifyDepositTransaction.ts │ │ ├── verifyTransactionBody.ts │ │ ├── verifyOutputTransaction.ts │ │ ├── verifyTypeofParams.ts │ │ ├── verifyType.ts │ │ ├── verifyCardTransaction.ts │ │ └── index.ts │ └── index.ts ├── models │ ├── transaction │ │ ├── CardType.ts │ │ ├── CardPayParams.ts │ │ ├── WithdrawParams.ts │ │ ├── PixParams.ts │ │ ├── DepositParams.ts │ │ ├── GetCardPerUserIdParams.ts │ │ ├── NewPixParams.ts │ │ ├── OutputTransactionParams.ts │ │ ├── DeleteTransactionParams.ts │ │ ├── TransactionParams.ts │ │ ├── CardTransactionParams.ts │ │ ├── DatabaseTransactionParams.ts │ │ └── index.ts │ ├── user │ │ ├── DeleteUserParams.ts │ │ ├── LoginUserParams.ts │ │ ├── UpdateUserEmailParams.ts │ │ ├── UpdateUserPhoneParams.ts │ │ ├── UpdateUserPasswordParams.ts │ │ ├── RefreshCardParams.ts │ │ ├── RefreshUserParams.ts │ │ ├── ReturnedDatabaseUserParams.ts │ │ ├── ValidateCardParams.ts │ │ ├── UpdateCardPasswordParams.ts │ │ ├── UserParams.ts │ │ ├── UpdateUserParams.ts │ │ ├── CardParams.ts │ │ ├── DatabaseUserParams.ts │ │ ├── InsertCardParams.ts │ │ ├── DatabaseCardParams.ts │ │ └── index.ts │ └── index.ts ├── error │ ├── index.ts │ ├── HttpStatusError.ts │ └── handleError.ts ├── server.ts ├── repositories │ ├── user │ │ ├── eraseUser.ts │ │ ├── refreshUserPassword.ts │ │ ├── getUserPerId.ts │ │ ├── getUserPerCpf.ts │ │ ├── getUserPerEmail.ts │ │ ├── getUserPerPhone.ts │ │ ├── refreshCardPassword.ts │ │ ├── refreshUserEmail.ts │ │ ├── refreshUserPhone.ts │ │ ├── refreshUser.ts │ │ ├── createNewUser.ts │ │ ├── getCardPerUserId.ts │ │ ├── index.ts │ │ ├── getCardsPerUserId.ts │ │ └── createCard.ts │ ├── transaction │ │ ├── dropTransactions.ts │ │ ├── dropTransaction.ts │ │ ├── createNewDeposit.ts │ │ ├── dropCards.ts │ │ ├── cardPay.ts │ │ ├── getCategoriePerId.ts │ │ ├── getTypeValue.ts │ │ ├── createNewPix.ts │ │ ├── removeValue.ts │ │ ├── createCardTransaction.ts │ │ ├── getTransaction.ts │ │ ├── getTransactions.ts │ │ ├── getBalancePerId.ts │ │ ├── createNewTransaction.ts │ │ ├── getTypedTransactions.ts │ │ └── index.ts │ └── index.ts ├── schemas │ ├── user │ │ ├── LoginUserSchema.ts │ │ ├── PasswordSchema.ts │ │ ├── CardSchema.ts │ │ ├── UserSchema.ts │ │ ├── UpdateUserSchema.ts │ │ ├── UpdateEmailSchema.ts │ │ ├── UpdatePhoneSchema.ts │ │ ├── UpdatePasswordSchema.ts │ │ ├── UpdateCardPasswordSchema.ts │ │ ├── GeneralCardSchema.ts │ │ ├── GeneralUserSchema.ts │ │ └── index.ts │ ├── transaction │ │ ├── DepositSchema.ts │ │ ├── PixSchema.ts │ │ ├── CardPaySchema.ts │ │ ├── TransactionSchema.ts │ │ ├── CardTransactionSchema.ts │ │ ├── TransactionWithdrawSchema.ts │ │ ├── GeneralTransactionSchema.ts │ │ └── index.ts │ └── index.ts ├── utils │ ├── encryptPassword.ts │ ├── dateFormatter.ts │ ├── index.ts │ ├── validatePassword.ts │ ├── createToken.ts │ └── getToken.ts ├── providers │ ├── user │ │ ├── validateCardType.ts │ │ ├── undefinedUser.ts │ │ ├── undefinedEmail.ts │ │ ├── verifyCpfExists.ts │ │ ├── verifyEmailExists.ts │ │ ├── verifyPhoneExists.ts │ │ ├── index.ts │ │ └── validateCard.ts │ ├── transaction │ │ ├── validatePix.ts │ │ ├── validateOutput.ts │ │ ├── verifyAccountTransactions.ts │ │ ├── verifyTransactionId.ts │ │ ├── validateTransaction.ts │ │ └── index.ts │ └── index.ts ├── routes │ ├── index.ts │ ├── swaggerRoutes.ts │ ├── renderAutoReq.ts │ ├── userRoutes.ts │ └── transactionRoutes.ts ├── data │ └── connection.ts ├── controllers │ ├── user │ │ ├── detailCards.ts │ │ ├── detailUser.ts │ │ ├── deleteUser.ts │ │ ├── loginUser.ts │ │ ├── insertUser.ts │ │ ├── updateUserEmail.ts │ │ ├── updateUserPassword.ts │ │ ├── updateUserPhone.ts │ │ ├── index.ts │ │ ├── updateUser.ts │ │ ├── updateCardPassword.ts │ │ └── insertCard.ts │ ├── transaction │ │ ├── getHistory.ts │ │ ├── summaryTransactions.ts │ │ ├── detailTransaction.ts │ │ ├── makeCardPay.ts │ │ ├── insertPix.ts │ │ ├── makeWithdraw.ts │ │ ├── insertDeposit.ts │ │ ├── insertTransaction.ts │ │ ├── insertCardTransaction.ts │ │ ├── index.ts │ │ └── deleteTransaction.ts │ └── index.ts ├── app.ts ├── services │ ├── transaction │ │ ├── insertTransactionAndReturn.ts │ │ ├── getHistoryAndReturn.ts │ │ ├── getTransactionAndReturn.ts │ │ ├── summaryTransactionsAndReturn.ts │ │ ├── deleteTransactionAndConfirm.ts │ │ ├── makeWithdrawAndReturn.ts │ │ ├── index.ts │ │ ├── insertDepositAndReturn.ts │ │ ├── makeCardPayAndReturn.ts │ │ ├── insertCardTransactionAndReturn.ts │ │ └── insertPixAndReturn.ts │ ├── user │ │ ├── getUserDetailsAndReturn.ts │ │ ├── deleteUserAndConfirm.ts │ │ ├── detailCardsAndReturn.ts │ │ ├── loginUserAndReturn.ts │ │ ├── updatePasswordAndConfirm.ts │ │ ├── updateEmailAndReturn.ts │ │ ├── updatePhoneAndReturn.ts │ │ ├── insertUserAndReturn.ts │ │ ├── updateCardPasswordAndConfirm.ts │ │ ├── index.ts │ │ ├── updateUserAndReturn.ts │ │ └── insertCardAndReturn.ts │ └── index.ts └── sql │ └── dump.sql ├── bun.lockb ├── nodemon.json ├── tests ├── models │ ├── transaction │ │ ├── index.ts │ │ ├── WithdrawModel.ts │ │ └── DepositModels.ts │ ├── user │ │ ├── index.ts │ │ ├── LoginModels.ts │ │ ├── UserModels.ts │ │ └── CardModels.ts │ └── index.ts ├── functions │ ├── transaction │ │ ├── index.ts │ │ ├── insertDeposit.ts │ │ └── makeWithdraw.ts │ ├── user │ │ ├── deleteCard.ts │ │ ├── deleteUser.ts │ │ ├── index.ts │ │ ├── insertCard.ts │ │ ├── unauthUser.ts │ │ └── insertUserAndLogin.ts │ └── index.ts ├── testsSetup.ts ├── user │ ├── detailUser.test.ts │ ├── loginUser.test.ts │ ├── detailCards.test.ts │ ├── deleteUser.test.ts │ ├── updateUserPassword.test.ts │ ├── insertUser.test.ts │ ├── updateUserPhone.test.ts │ ├── updateUserEmail.test.ts │ ├── updateCardPassword.test.ts │ └── updateUser.test.ts └── transaction │ ├── getHistory.test.ts │ ├── summaryTransactions.test.ts │ ├── detailTransaction.test.ts │ ├── deleteTransaction.test.ts │ ├── insertTransaction.test.ts │ ├── makeWithdraw.test.ts │ ├── insertDeposit.test.ts │ ├── makeCardPay.test.ts │ ├── insertPix.test.ts │ └── insertCardTransaction.test.ts ├── .dockerignore ├── .editorconfig ├── .env.example ├── .env.test.example ├── Dockerfile ├── .eslintrc.json ├── jest.config.js ├── LICENSE └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | .env.test 4 | -------------------------------------------------------------------------------- /src/jwt/jwtPassword.ts: -------------------------------------------------------------------------------- 1 | export default process.env.JWT_PASS; 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bush1D3v/tsbank_api/HEAD/bun.lockb -------------------------------------------------------------------------------- /src/middlewares/auth/index.ts: -------------------------------------------------------------------------------- 1 | import auth from "./auth"; 2 | 3 | export default auth; 4 | -------------------------------------------------------------------------------- /src/models/transaction/CardType.ts: -------------------------------------------------------------------------------- 1 | export interface CardType { 2 | card_type: string; 3 | }; 4 | -------------------------------------------------------------------------------- /src/models/user/DeleteUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface DeleteUserParams { 2 | password: string; 3 | } 4 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["src", "./swagger.json"], 3 | "ext": "ts", 4 | "exec": "ts-node ./src/server.ts" 5 | } 6 | -------------------------------------------------------------------------------- /src/models/transaction/CardPayParams.ts: -------------------------------------------------------------------------------- 1 | export interface CardPayParams { 2 | value: number; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/user/LoginUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface LoginUserParams { 2 | email: string; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/transaction/WithdrawParams.ts: -------------------------------------------------------------------------------- 1 | export interface WithdrawParams { 2 | value: number; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/transaction/PixParams.ts: -------------------------------------------------------------------------------- 1 | export interface PixParams { 2 | value: number; 3 | cpf: string; 4 | password: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/models/user/UpdateUserEmailParams.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUserEmailParams { 2 | new_email: string; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/user/UpdateUserPhoneParams.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUserPhoneParams { 2 | password: string; 3 | new_phone: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/models/transaction/DepositParams.ts: -------------------------------------------------------------------------------- 1 | export interface DepositParams { 2 | value: number; 3 | email: string; 4 | password: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/models/transaction/GetCardPerUserIdParams.ts: -------------------------------------------------------------------------------- 1 | export interface GetCardPerUserIdParams { 2 | userId: number; 3 | cardType: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/models/transaction/NewPixParams.ts: -------------------------------------------------------------------------------- 1 | export interface NewPixParams { 2 | user_id: number; 3 | value: number; 4 | cpf: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/transaction/OutputTransactionParams.ts: -------------------------------------------------------------------------------- 1 | export interface OutputTransactionParams { 2 | value: number; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/user/UpdateUserPasswordParams.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUserPasswordParams { 2 | new_password: string; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/transaction/DeleteTransactionParams.ts: -------------------------------------------------------------------------------- 1 | export interface DeleteTransactionParams { 2 | transaction_id: number; 3 | password: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/models/transaction/TransactionParams.ts: -------------------------------------------------------------------------------- 1 | export interface TransactionParams { 2 | type: string; 3 | description: string; 4 | value: number; 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/user/RefreshCardParams.ts: -------------------------------------------------------------------------------- 1 | export interface RefreshCardParams { 2 | card_type: string; 3 | new_password: string; 4 | card_id: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/models/user/RefreshUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface RefreshUserParams { 2 | new_email: string; 3 | new_phone: string; 4 | new_password: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/user/ReturnedDatabaseUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface ReturnedDatabaseUserParams { 2 | id: number; 3 | name: string; 4 | email: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/user/ValidateCardParams.ts: -------------------------------------------------------------------------------- 1 | export interface ValidateCardParams { 2 | card_type: string; 3 | user_id: number; 4 | card_number: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/error/index.ts: -------------------------------------------------------------------------------- 1 | import handleError from "./handleError"; 2 | import HttpStatusError from "./HttpStatusError"; 3 | 4 | export { handleError, HttpStatusError }; 5 | -------------------------------------------------------------------------------- /src/models/transaction/CardTransactionParams.ts: -------------------------------------------------------------------------------- 1 | export interface CardTransactionParams { 2 | password: string; 3 | card_type: string; 4 | value: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import app from "./app"; 2 | 3 | const PORT = process.env.PORT || 3001; 4 | 5 | const server = app.listen(PORT); 6 | 7 | export default server; 8 | -------------------------------------------------------------------------------- /src/models/user/UpdateCardPasswordParams.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateCardPasswordParams { 2 | card_type: string; 3 | password: string; 4 | new_password: string; 5 | }; 6 | -------------------------------------------------------------------------------- /src/models/user/UserParams.ts: -------------------------------------------------------------------------------- 1 | export interface UserParams { 2 | name: string; 3 | email: string; 4 | password: string; 5 | cpf: string; 6 | phone: string; 7 | } 8 | -------------------------------------------------------------------------------- /tests/models/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import deposit from "./DepositModels"; 2 | import withdraw from "./WithdrawModel"; 3 | 4 | export { 5 | deposit, 6 | withdraw 7 | }; 8 | -------------------------------------------------------------------------------- /src/models/user/UpdateUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateUserParams { 2 | new_email: string; 3 | new_password: string; 4 | new_phone: string; 5 | password: string; 6 | }; 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .dockerignore 3 | .editorconfig 4 | .env.example 5 | .env.test.example 6 | .eslintrc.json 7 | .gitignore 8 | bun.lockb 9 | LICENSE 10 | README.md 11 | -------------------------------------------------------------------------------- /src/repositories/user/eraseUser.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function eraseUser(id: number) { 4 | await db("users").delete().where({ id }); 5 | } 6 | -------------------------------------------------------------------------------- /src/schemas/user/LoginUserSchema.ts: -------------------------------------------------------------------------------- 1 | import UserSchema from "./UserSchema"; 2 | 3 | const LoginUserSchema = UserSchema.omit([ "name", "cpf", "phone" ]); 4 | 5 | export default LoginUserSchema; 6 | -------------------------------------------------------------------------------- /src/schemas/user/PasswordSchema.ts: -------------------------------------------------------------------------------- 1 | import LoginUserSchema from "./LoginUserSchema"; 2 | 3 | const PasswordSchema = LoginUserSchema.omit([ "email" ]); 4 | 5 | export default PasswordSchema; 6 | -------------------------------------------------------------------------------- /tests/functions/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import insertDeposit from "./insertDeposit"; 2 | import makeWithdraw from "./makeWithdraw"; 3 | 4 | export { 5 | insertDeposit, 6 | makeWithdraw 7 | }; 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /src/schemas/user/CardSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralCardSchema from "./GeneralCardSchema"; 2 | 3 | const CardSchema = GeneralCardSchema.omit([ "value", "new_password" ]); 4 | 5 | export default CardSchema; 6 | -------------------------------------------------------------------------------- /tests/functions/user/deleteCard.ts: -------------------------------------------------------------------------------- 1 | import db from "../../../src/data/connection"; 2 | 3 | export default async function deleteCard(cardType: string | null) { 4 | await db(cardType + "_cards").delete(); 5 | }; 6 | -------------------------------------------------------------------------------- /src/schemas/user/UserSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralUserSchema from "./GeneralUserSchema"; 2 | 3 | const UserSchema = GeneralUserSchema.omit([ "new_email", "new_password", "new_phone" ]); 4 | 5 | export default UserSchema; 6 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | DB_CLIENT=your_client 2 | DB_HOST=your_host 3 | DB_USER=your_user 4 | DB_PASS=your_password 5 | DB_DATA=your_database 6 | 7 | PORT=your_port 8 | 9 | JWT_PASS=your_jwt 10 | JWT_EXPIRES=your_expiration 11 | -------------------------------------------------------------------------------- /src/models/user/CardParams.ts: -------------------------------------------------------------------------------- 1 | export interface CardParams { 2 | card_number: string; 3 | cardholder_name: string; 4 | expiration_date: string; 5 | cvv: string; 6 | password: string; 7 | card_type: string; 8 | }; 9 | -------------------------------------------------------------------------------- /src/repositories/transaction/dropTransactions.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function dropTransactions(user_id: number) { 4 | await db("transactions").delete().where({ user_id }); 5 | } 6 | -------------------------------------------------------------------------------- /src/schemas/user/UpdateUserSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralUserSchema from "./GeneralUserSchema"; 2 | 3 | const UpdateUserSchema = GeneralUserSchema.omit([ "name", "email", "cpf", "phone" ]); 4 | 5 | export default UpdateUserSchema; 6 | -------------------------------------------------------------------------------- /src/utils/encryptPassword.ts: -------------------------------------------------------------------------------- 1 | import { hash } from "bcrypt"; 2 | 3 | export default async function encryptPassword(password: string) { 4 | const cryptPassword = await hash(password, 10); 5 | 6 | return cryptPassword; 7 | }; 8 | -------------------------------------------------------------------------------- /tests/models/transaction/WithdrawModel.ts: -------------------------------------------------------------------------------- 1 | import { WithdrawParams } from "../../../src/models"; 2 | 3 | const withdraw: WithdrawParams = { 4 | "value": 30000, 5 | "password": "vtjln123" 6 | }; 7 | 8 | export default withdraw; 9 | -------------------------------------------------------------------------------- /src/models/user/DatabaseUserParams.ts: -------------------------------------------------------------------------------- 1 | export interface DatabaseUserParams { 2 | id: number; 3 | balance: number; 4 | name: string; 5 | email: string; 6 | password: string; 7 | cpf: string; 8 | phone: string; 9 | }; 10 | -------------------------------------------------------------------------------- /src/schemas/transaction/DepositSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 2 | 3 | const DepositSchema = GeneralTransactionSchema.omit([ "type", "description", "cpf" ]); 4 | 5 | export default DepositSchema; 6 | -------------------------------------------------------------------------------- /src/schemas/transaction/PixSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 2 | 3 | const PixSchema = GeneralTransactionSchema.omit([ "email", "description", "email", "type" ]); 4 | 5 | export default PixSchema; 6 | -------------------------------------------------------------------------------- /src/error/HttpStatusError.ts: -------------------------------------------------------------------------------- 1 | export default class HttpStatusError extends Error { 2 | statusCode: number; 3 | 4 | constructor(message: string, statusCode: number) { 5 | super(message); 6 | this.statusCode = statusCode; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/repositories/transaction/dropTransaction.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function dropTransaction(transaction_id: number) { 4 | await db("transactions").delete().where({ "id": transaction_id }); 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/dateFormatter.ts: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | 3 | export default function dateFormatter(date: string) { 4 | const formattedDate = dayjs(date).subtract(3, "hour").format("YYYY/MM/DD HH:mm:ss"); 5 | 6 | return formattedDate; 7 | } 8 | -------------------------------------------------------------------------------- /src/schemas/transaction/CardPaySchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 2 | 3 | const CardPaySchema = GeneralTransactionSchema.omit([ "description", "type", "email", "cpf" ]); 4 | 5 | export default CardPaySchema; 6 | -------------------------------------------------------------------------------- /src/schemas/transaction/TransactionSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 2 | 3 | const TransactionSchema = GeneralTransactionSchema.omit([ "password", "email", "cpf" ]); 4 | 5 | export default TransactionSchema; 6 | -------------------------------------------------------------------------------- /src/models/transaction/DatabaseTransactionParams.ts: -------------------------------------------------------------------------------- 1 | import { TransactionParams } from "./TransactionParams"; 2 | 3 | export interface DatabaseTransactionParams extends TransactionParams { 4 | id: number; 5 | user_id: number; 6 | date: string; 7 | }; 8 | -------------------------------------------------------------------------------- /src/repositories/transaction/createNewDeposit.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function createNewDeposit(email: string, value: number) { 4 | await db("users").increment({ "balance": value }).where({ email }); 5 | }; 6 | -------------------------------------------------------------------------------- /src/schemas/user/UpdateEmailSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralUserSchema from "./GeneralUserSchema"; 2 | 3 | const UpdateEmailSchema = GeneralUserSchema.omit([ "new_password", "email", "name", "cpf", "phone", "new_phone" ]); 4 | 5 | export default UpdateEmailSchema; 6 | -------------------------------------------------------------------------------- /src/schemas/user/UpdatePhoneSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralUserSchema from "./GeneralUserSchema"; 2 | 3 | const UpdatePhoneSchema = GeneralUserSchema.omit([ "name", "email", "cpf", "phone", "new_email", "new_password" ]); 4 | 5 | export default UpdatePhoneSchema; 6 | -------------------------------------------------------------------------------- /src/providers/user/validateCardType.ts: -------------------------------------------------------------------------------- 1 | export default function validateCardType(card_type: string) { 2 | if (card_type.toLowerCase() !== "credit" && card_type.toLowerCase() !== "debit") { 3 | throw new Error("invalid value of 'Card Type'"); 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /src/schemas/user/UpdatePasswordSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralUserSchema from "./GeneralUserSchema"; 2 | 3 | const UpdatePasswordSchema = GeneralUserSchema.omit([ "new_email", "name", "email", "cpf", "phone", "new_phone" ]); 4 | 5 | export default UpdatePasswordSchema; 6 | -------------------------------------------------------------------------------- /.env.test.example: -------------------------------------------------------------------------------- 1 | DB_CLIENT=your_test_client 2 | DB_HOST=your_test_host 3 | DB_USER=your_test_user 4 | DB_PASS=your_test_password 5 | DB_DATA=your_test_database 6 | 7 | PORT=your_test_port 8 | 9 | JWT_PASS=your_test_jwt 10 | JWT_EXPIRES=your_test_expiration 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine AS builder 2 | 3 | WORKDIR /app 4 | 5 | COPY package.json ./ 6 | COPY . . 7 | 8 | RUN yarn install 9 | 10 | FROM builder AS final 11 | 12 | COPY --from=builder /app /app 13 | 14 | EXPOSE 3001 15 | 16 | CMD ["yarn", "dev"] 17 | -------------------------------------------------------------------------------- /src/providers/user/undefinedUser.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | 3 | export default function undefinedUser(user: undefined | object) { 4 | if (typeof user === "undefined") { 5 | throw new HttpStatusError("user not found", 404); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /src/repositories/transaction/dropCards.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function dropCards(user_id: number) { 4 | await db("credit_cards").delete().where({ user_id }); 5 | await db("debit_cards").delete().where({ user_id }); 6 | } 7 | -------------------------------------------------------------------------------- /tests/models/transaction/DepositModels.ts: -------------------------------------------------------------------------------- 1 | import { DepositParams } from "../../../src/models"; 2 | 3 | const deposit: DepositParams = { 4 | "value": 30000, 5 | "email": "victorjln@gmail.com", 6 | "password": "vtjln123" 7 | }; 8 | 9 | export default deposit; 10 | -------------------------------------------------------------------------------- /src/repositories/transaction/cardPay.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function cardPay(value: number, userId: number) { 4 | await db("credit_cards").increment("balance", value) 5 | .where({ 6 | "user_id": userId 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/schemas/transaction/CardTransactionSchema.ts: -------------------------------------------------------------------------------- 1 | import { GeneralCardSchema } from "../user"; 2 | 3 | const CardTransactionSchema = GeneralCardSchema.omit([ "card_number", "cardholder_name", "cvv", "expiration_date", "new_password" ]); 4 | 5 | export default CardTransactionSchema; 6 | -------------------------------------------------------------------------------- /src/repositories/user/refreshUserPassword.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function refreshUserPassword(id: number, new_password: string) { 4 | await db("users").update({ "password": new_password }) 5 | .where({ 6 | id 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/schemas/transaction/TransactionWithdrawSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 2 | 3 | const TransactionWithdrawSchema = GeneralTransactionSchema.omit([ "description", "type", "email", "cpf" ]); 4 | 5 | export default TransactionWithdrawSchema; 6 | -------------------------------------------------------------------------------- /src/schemas/user/UpdateCardPasswordSchema.ts: -------------------------------------------------------------------------------- 1 | import GeneralCardSchema from "./GeneralCardSchema"; 2 | 3 | const UpdateCardPasswordSchema = GeneralCardSchema.omit([ "value", "cvv", "expiration_date", "card_number", "cardholder_name" ]); 4 | 5 | export default UpdateCardPasswordSchema; 6 | -------------------------------------------------------------------------------- /src/models/user/InsertCardParams.ts: -------------------------------------------------------------------------------- 1 | export interface InsertCardParams { 2 | card_number: string; 3 | cardholder_name: string; 4 | expiration_date: string; 5 | cvv: string; 6 | user_id: number; 7 | balance: number; 8 | password: string; 9 | card_type: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/providers/transaction/validatePix.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | 3 | export default function validatePix(reqCpf: string, userCpf: string) { 4 | if (reqCpf === userCpf) { 5 | throw new HttpStatusError("it's not possible to make a pix for yourself", 400); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /tests/models/user/index.ts: -------------------------------------------------------------------------------- 1 | import { credit, debit } from "./CardModels"; 2 | import { loginUser, loginUser2 } from "./LoginModels"; 3 | import { user, user2 } from "./UserModels"; 4 | 5 | export { 6 | user, 7 | user2, 8 | loginUser, 9 | loginUser2, 10 | credit, 11 | debit 12 | }; 13 | -------------------------------------------------------------------------------- /src/repositories/user/getUserPerId.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseUserParams } from "../../models"; 3 | 4 | export default async function getUserPerId(id: number) { 5 | const user: DatabaseUserParams = await db("users").where({ id }).first(); 6 | 7 | return user; 8 | }; 9 | -------------------------------------------------------------------------------- /src/repositories/user/getUserPerCpf.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseUserParams } from "../../models"; 3 | 4 | export default async function getUserPerCpf(cpf: string) { 5 | const user: DatabaseUserParams = await db("users").where({ cpf }).first(); 6 | 7 | return user; 8 | }; 9 | -------------------------------------------------------------------------------- /src/models/user/DatabaseCardParams.ts: -------------------------------------------------------------------------------- 1 | export interface DatabaseCardParams { 2 | id: number; 3 | card_number: string; 4 | cardholder_name: string; 5 | expiration_date: string; 6 | cvv: string; 7 | user_id: number; 8 | created_at: string; 9 | balance: number; 10 | password: string; 11 | }; 12 | -------------------------------------------------------------------------------- /src/repositories/user/getUserPerEmail.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseUserParams } from "../../models"; 3 | 4 | export default async function getUserPerEmail(email: string) { 5 | const user: DatabaseUserParams = await db("users").where({ email }).first(); 6 | 7 | return user; 8 | }; 9 | -------------------------------------------------------------------------------- /src/repositories/user/getUserPerPhone.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseUserParams } from "../../models"; 3 | 4 | export default async function getUserPerPhone(phone: string) { 5 | const user: DatabaseUserParams = await db("users").where({ phone }).first(); 6 | 7 | return user; 8 | }; 9 | -------------------------------------------------------------------------------- /src/providers/transaction/validateOutput.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | 3 | export default function validateOutput(actualBalance: number, outputValue: number) { 4 | if (actualBalance < outputValue) { 5 | throw new HttpStatusError("insufficient balance to perform the transaction", 400); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /src/repositories/transaction/getCategoriePerId.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function getCategoriePerId(id: number) { 4 | const response: string = await db("categories") 5 | .where({ id }) 6 | .select("description") 7 | .first(); 8 | 9 | return response; 10 | }; 11 | -------------------------------------------------------------------------------- /src/routes/index.ts: -------------------------------------------------------------------------------- 1 | import userRoutes from "./userRoutes"; 2 | import transactionRoutes from "./transactionRoutes"; 3 | import swaggerRoutes from "./swaggerRoutes"; 4 | import renderAutoReq from "./renderAutoReq"; 5 | 6 | export { 7 | userRoutes, 8 | transactionRoutes, 9 | swaggerRoutes, 10 | renderAutoReq 11 | }; 12 | -------------------------------------------------------------------------------- /src/data/connection.ts: -------------------------------------------------------------------------------- 1 | import knex from "knex"; 2 | 3 | const db = knex({ 4 | client: process.env.DB_CLIENT, 5 | connection: { 6 | host: process.env.DB_HOST, 7 | user: process.env.DB_USER, 8 | password: process.env.DB_PASS, 9 | database: process.env.DB_DATA, 10 | } 11 | }); 12 | 13 | export default db; 14 | -------------------------------------------------------------------------------- /src/providers/user/undefinedEmail.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { DatabaseUserParams } from "../../models"; 3 | 4 | export default function undefinedEmail(user: undefined | DatabaseUserParams) { 5 | if (typeof user?.email === "undefined") { 6 | throw new HttpStatusError("invalid email", 401); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/routes/swaggerRoutes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import swaggerUi from "swagger-ui-express"; 3 | import swaggerDocument from "../../swagger.json"; 4 | 5 | const swaggerRoutes = express(); 6 | 7 | swaggerRoutes.get("/", swaggerUi.setup(swaggerDocument)); 8 | swaggerRoutes.use(swaggerUi.serve); 9 | 10 | export default swaggerRoutes; 11 | -------------------------------------------------------------------------------- /tests/models/user/LoginModels.ts: -------------------------------------------------------------------------------- 1 | import { LoginUserParams } from "../../../src/models"; 2 | 3 | const loginUser: LoginUserParams = { 4 | email: "victorjln@gmail.com", 5 | password: "vtjln123" 6 | }; 7 | 8 | const loginUser2 = { 9 | email: "victorjln2@gmail.com", 10 | password: "vtjln123" 11 | }; 12 | 13 | export { loginUser, loginUser2 }; 14 | -------------------------------------------------------------------------------- /tests/functions/user/deleteUser.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../../src/server"; 3 | 4 | export default async function deleteUser(token: string | undefined, password: string | null) { 5 | await request(server) 6 | .delete("/user") 7 | .set("Authorization", `Bearer ${token}`) 8 | .send({ password }); 9 | }; 10 | -------------------------------------------------------------------------------- /tests/testsSetup.ts: -------------------------------------------------------------------------------- 1 | import db from "../src/data/connection"; 2 | import server from "../src/server"; 3 | 4 | afterAll(async () => { 5 | await db("debit_cards").delete("*"); 6 | await db("credit_cards").delete("*"); 7 | await db("transactions").delete("*"); 8 | await db("users").delete("*"); 9 | await db.destroy(); 10 | server.close(); 11 | }); 12 | -------------------------------------------------------------------------------- /src/routes/renderAutoReq.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import { Request, Response } from "express"; 3 | 4 | const renderReq = express(); 5 | 6 | async function renderAutoReq(req: Request, res: Response) { 7 | return res.send("Pong"); 8 | }; 9 | 10 | renderReq.get( 11 | "/ping", 12 | renderAutoReq 13 | ); 14 | 15 | export default renderAutoReq; 16 | -------------------------------------------------------------------------------- /tests/models/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | user, 3 | user2, 4 | loginUser, 5 | loginUser2, 6 | credit, 7 | debit 8 | } from "./user"; 9 | import { 10 | deposit, 11 | withdraw 12 | } from "./transaction"; 13 | 14 | export { 15 | user, 16 | user2, 17 | loginUser, 18 | loginUser2, 19 | credit, 20 | debit, 21 | deposit, 22 | withdraw 23 | }; 24 | -------------------------------------------------------------------------------- /src/repositories/transaction/getTypeValue.ts: -------------------------------------------------------------------------------- 1 | import { DatabaseTransactionParams } from "../../models"; 2 | 3 | export default function getTypeValue(typedTransactions: DatabaseTransactionParams[]) { 4 | let finalValue = 0; 5 | 6 | for (let transaction of typedTransactions) { 7 | finalValue += transaction.value; 8 | } 9 | 10 | return finalValue; 11 | }; 12 | -------------------------------------------------------------------------------- /src/providers/user/verifyCpfExists.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { getUserPerCpf } from "../../repositories"; 3 | 4 | export default async function verifyCpfExists(cpf: string) { 5 | const cpfExists = await getUserPerCpf(cpf); 6 | 7 | if (cpfExists) { 8 | throw new HttpStatusError("this cpf already used per other user", 409); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/functions/user/index.ts: -------------------------------------------------------------------------------- 1 | import deleteCard from "./deleteCard"; 2 | import deleteUser from "./deleteUser"; 3 | import insertCard from "./insertCard"; 4 | import insertUserAndLogin from "./insertUserAndLogin"; 5 | import unauthUser from "./unauthUser"; 6 | 7 | export { 8 | deleteUser, 9 | deleteCard, 10 | insertCard, 11 | insertUserAndLogin, 12 | unauthUser 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | import encryptPassword from "./encryptPassword"; 2 | import createToken from "./createToken"; 3 | import getToken from "./getToken"; 4 | import validatePassword from "./validatePassword"; 5 | import dateFormatter from "./dateFormatter"; 6 | 7 | export { 8 | encryptPassword, 9 | createToken, 10 | getToken, 11 | validatePassword, 12 | dateFormatter 13 | }; 14 | -------------------------------------------------------------------------------- /src/repositories/transaction/createNewPix.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { NewPixParams } from "../../models"; 3 | 4 | export default async function createNewPix(params: NewPixParams) { 5 | await db("users").increment({ "balance": params.value }).where({ cpf: params.cpf }); 6 | await db("users").decrement({ "balance": params.value }).where({ id: params.user_id }); 7 | }; 8 | -------------------------------------------------------------------------------- /src/repositories/user/refreshCardPassword.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { RefreshCardParams } from "../../models"; 3 | 4 | export default async function refreshCardPassword(params: RefreshCardParams) { 5 | await db(params.card_type.toLowerCase() + "_cards").update({ 6 | password: params.new_password 7 | }).where({ 8 | id: params.card_id 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /tests/functions/user/insertCard.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../../src/server"; 3 | import { CardParams } from "../../../src/models"; 4 | 5 | export default async function insertCard(token: string | undefined, card: CardParams) { 6 | await request(server) 7 | .post("/card") 8 | .set("Authorization", `Bearer ${token}`) 9 | .send(card); 10 | }; 11 | -------------------------------------------------------------------------------- /src/providers/transaction/verifyAccountTransactions.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { DatabaseTransactionParams } from "../../models"; 3 | 4 | export default function verifyAccountTransactions(transaction: DatabaseTransactionParams[]) { 5 | if (transaction.length < 1) { 6 | throw new HttpStatusError("your account does not have any registered transaction", 404); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /src/providers/user/verifyEmailExists.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { getUserPerEmail } from "../../repositories"; 3 | 4 | export default async function verifyEmailExists(email: string) { 5 | const emailExists = await getUserPerEmail(email); 6 | 7 | if (emailExists) { 8 | throw new HttpStatusError("this email already used per other user", 409); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/providers/user/verifyPhoneExists.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { getUserPerPhone } from "../../repositories"; 3 | 4 | export default async function verifyPhoneExists(phone: string) { 5 | const phoneExists = await getUserPerPhone(phone); 6 | 7 | if (phoneExists) { 8 | throw new HttpStatusError("this phone already used per other user", 409); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/functions/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | deleteCard, 3 | deleteUser, 4 | insertCard, 5 | insertUserAndLogin, 6 | unauthUser 7 | } from "./user"; 8 | import { 9 | insertDeposit, 10 | makeWithdraw 11 | } from "./transaction"; 12 | 13 | export { 14 | deleteCard, 15 | deleteUser, 16 | insertCard, 17 | insertUserAndLogin, 18 | unauthUser, 19 | insertDeposit, 20 | makeWithdraw 21 | }; 22 | -------------------------------------------------------------------------------- /src/utils/validatePassword.ts: -------------------------------------------------------------------------------- 1 | import { compare } from "bcrypt"; 2 | import { HttpStatusError } from "../error"; 3 | 4 | export default async function validatePassword(reqPassword: string, dataPassword: string) { 5 | const password = await compare(reqPassword, dataPassword); 6 | 7 | if (!password) { 8 | throw new HttpStatusError("invalid password", 401); 9 | } 10 | 11 | return password; 12 | }; 13 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "parser": "@typescript-eslint/parser", 8 | "parserOptions": { 9 | "ecmaVersion": "latest", 10 | "sourceType": "module" 11 | }, 12 | "plugins": [ 13 | "@typescript-eslint" 14 | ], 15 | "rules": { 16 | "quotes": ["error", "double"], 17 | "semi": ["error", "always"] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/providers/transaction/verifyTransactionId.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { getTransaction } from "../../repositories"; 3 | 4 | export default async function verifyTransactiontransaction_id(transaction_id: number) { 5 | const transaction = await getTransaction(transaction_id); 6 | 7 | if (!transaction) { 8 | throw new HttpStatusError("transaction not found", 404); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/repositories/user/refreshUserEmail.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | type EmailDate = { 4 | email: string 5 | } 6 | 7 | export default async function refreshUserEmail(id: number, new_email: string) { 8 | const returnedEmail: EmailDate[] = await db("users").update({ "email": new_email }) 9 | .where({ 10 | id 11 | }).returning([ "email" ]); 12 | 13 | return returnedEmail[ 0 ]; 14 | }; 15 | -------------------------------------------------------------------------------- /src/repositories/user/refreshUserPhone.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | type PhoneData = { 4 | phone: string; 5 | }; 6 | 7 | export default async function refreshUserPhone(phone: string, new_phone: string) { 8 | const returnedPhone: PhoneData[] = await db("users").update({ "phone": new_phone }) 9 | .where({ 10 | phone 11 | }).returning([ "phone" ]); 12 | return returnedPhone[ 0 ]; 13 | }; 14 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | const { config } = require("dotenv"); 2 | 3 | config({ path: ".env.test" }); 4 | 5 | module.exports = { 6 | preset: "ts-jest", 7 | testEnvironment: "node", 8 | moduleFileExtensions: ["ts", "js"], 9 | setupFilesAfterEnv: ["./tests/testsSetup.ts"], 10 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.[tj]s$", 11 | transform: { 12 | "^.+\\.ts$": ["ts-jest", { tsconfig: "tsconfig.json" }], 13 | }, 14 | }; 15 | -------------------------------------------------------------------------------- /tests/functions/user/unauthUser.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import { Server } from "http"; 3 | 4 | let response: request.Response; 5 | 6 | type HttpMethod = "get" | "post" | "put" | "delete" | "patch"; 7 | 8 | export default async function unauthUser(method: HttpMethod, server: Server, url: string) { 9 | response = await request(server) 10 | [ method ]("/" + url) 11 | .send(); 12 | 13 | return response; 14 | }; 15 | -------------------------------------------------------------------------------- /src/providers/transaction/validateTransaction.ts: -------------------------------------------------------------------------------- 1 | import { HttpStatusError } from "../../error"; 2 | import { getTransaction } from "../../repositories"; 3 | 4 | export default async function validateTransaction(transaction_id: number, user_id: number) { 5 | const transaction = await getTransaction(transaction_id); 6 | 7 | if (transaction.user_id != user_id) { 8 | throw new HttpStatusError("transaction not found", 404); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /src/repositories/transaction/removeValue.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function removeValue(accountItem: string, value: number, user_id: number) { 4 | if (accountItem.toLowerCase() === "credit") { 5 | await db("credit_cards").decrement("balance", value) 6 | .where({ user_id }); 7 | } else { 8 | await db("users").decrement("balance", value) 9 | .where({ id: user_id }); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /src/controllers/user/detailCards.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { detailCardsAndReturn } from "../../services"; 4 | 5 | export default async function detailCards(req: Request, res: Response) { 6 | try { 7 | const cards = await detailCardsAndReturn(req); 8 | 9 | return res.json(cards); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/controllers/user/detailUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { getUserDetailsAndReturn } from "../../services"; 4 | 5 | export default async function detailUser(req: Request, res: Response) { 6 | try { 7 | const user = await getUserDetailsAndReturn(req); 8 | 9 | return res.json(user); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUserBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { UserSchema } from "../../schemas"; 3 | import { handleError } from "../../error"; 4 | 5 | export default async function verifyUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await UserSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyPixValue.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { PixSchema } from "../../schemas"; 4 | 5 | export default async function verifyPixValue(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await PixSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyPassword.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { PasswordSchema } from "../../schemas"; 4 | 5 | export default async function verifyPassword(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await PasswordSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/utils/createToken.ts: -------------------------------------------------------------------------------- 1 | import { sign } from "jsonwebtoken"; 2 | import jwtPassword from "../jwt/jwtPassword"; 3 | import { DatabaseUserParams } from "../models"; 4 | 5 | export default function createToken(user: DatabaseUserParams) { 6 | const token = sign({ id: user.id }, jwtPassword, { expiresIn: process.env.JWT_EXPIRES }); 7 | 8 | const { password: _, ...logedUser } = user; 9 | 10 | return { 11 | user: logedUser, 12 | token 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyCardPay.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { CardPaySchema } from "../../schemas"; 4 | 5 | export default async function verifyCardPay(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await CardPaySchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/providers/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import validateOutput from "./validateOutput"; 2 | import validatePix from "./validatePix"; 3 | import validateTransaction from "./validateTransaction"; 4 | import verifyAccountTransactions from "./verifyAccountTransactions"; 5 | import verifyTransactionId from "./verifyTransactionId"; 6 | 7 | export { 8 | verifyTransactionId, 9 | validateTransaction, 10 | validatePix, 11 | validateOutput, 12 | verifyAccountTransactions 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyLoginUserBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { LoginUserSchema } from "../../schemas"; 4 | 5 | export default async function verifyLoginUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await LoginUserSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUpdateUserBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateUserSchema } from "../../schemas"; 4 | 5 | export default async function verifyUpdateUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await UpdateUserSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | import cors from "cors"; 3 | dotenv.config(); 4 | 5 | import express from "express"; 6 | import { 7 | userRoutes, 8 | transactionRoutes, 9 | swaggerRoutes, 10 | renderAutoReq 11 | } from "./routes"; 12 | 13 | const app = express(); 14 | 15 | app.use(cors()); 16 | app.use(express.json()); 17 | app.use(swaggerRoutes); 18 | app.use(userRoutes); 19 | app.use(transactionRoutes); 20 | app.use(renderAutoReq); 21 | 22 | export default app; 23 | -------------------------------------------------------------------------------- /src/controllers/transaction/getHistory.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { getHistoryAndReturn } from "../../services"; 4 | 5 | export default async function getHistory(req: Request, res: Response) { 6 | try { 7 | const filteredTransactions = await getHistoryAndReturn(req); 8 | 9 | return res.json(filteredTransactions); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyDepositTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { DepositSchema } from "../../schemas"; 4 | 5 | export default async function verifyDepositTransaction(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await DepositSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUpdatePhoneUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdatePhoneSchema } from "../../schemas"; 4 | 5 | export default async function verifyUpdatePhoneUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await UpdatePhoneSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyTransactionBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { TransactionSchema } from "../../schemas"; 4 | 5 | export default async function verifyTransactionBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await TransactionSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUpdateEmailUserBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateEmailSchema } from "../../schemas"; 4 | 5 | export default async function verifyUpdateEmailUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await UpdateEmailSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/schemas/transaction/GeneralTransactionSchema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from "yup"; 2 | 3 | const GeneralTransactionSchema = yup.object({ 4 | type: yup.string().min(5).max(6).required(), 5 | description: yup.string().required(), 6 | value: yup.number().min(0.01).required(), 7 | password: yup.string().min(8).max(16).required(), 8 | email: yup.string().email().max(75).required(), 9 | cpf: yup.string().min(11).max(11).required() 10 | }); 11 | 12 | export default GeneralTransactionSchema; 13 | -------------------------------------------------------------------------------- /src/repositories/transaction/createCardTransaction.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | export default async function createCardTransaction(cardType: string, user_id: number, value: number) { 4 | if (cardType.toLowerCase() === "credit") { 5 | await db(cardType.toLowerCase() + "_cards").decrement("balance", value).where({ 6 | user_id 7 | }); 8 | } else { 9 | await db("users").decrement("balance", value).where({ 10 | id: user_id 11 | }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /tests/models/user/UserModels.ts: -------------------------------------------------------------------------------- 1 | import { UserParams } from "../../../src/models"; 2 | 3 | const user: UserParams = { 4 | name: "Victor Navarro", 5 | cpf: "12345678931", 6 | phone: "21123456789", 7 | email: "victorjln@gmail.com", 8 | password: "vtjln123" 9 | }; 10 | 11 | const user2: UserParams = { 12 | name: "Victor José", 13 | cpf: "12345678921", 14 | phone: "31123456789", 15 | email: "victorjln2@gmail.com", 16 | password: "vtjln123" 17 | }; 18 | 19 | export { user, user2 }; 20 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUpdatePasswordUserBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdatePasswordSchema } from "../../schemas"; 4 | 5 | export default async function verifyUpdatePasswordUserBody(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await UpdatePasswordSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /tests/functions/transaction/insertDeposit.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../../src/server"; 3 | import { DepositParams } from "../../../src/models"; 4 | 5 | let response: request.Response; 6 | 7 | export default async function insertDeposit(token: string | undefined, deposit: DepositParams) { 8 | response = await request(server) 9 | .post("/deposit") 10 | .set("Authorization", `Bearer ${token}`) 11 | .send(deposit); 12 | 13 | return response; 14 | }; 15 | -------------------------------------------------------------------------------- /tests/functions/transaction/makeWithdraw.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../../src/server"; 3 | import { WithdrawParams } from "../../../src/models"; 4 | 5 | let response: request.Response; 6 | 7 | export default async function makeWithdraw(token: string | undefined, withdraw: WithdrawParams) { 8 | response = await request(server) 9 | .post("/withdraw") 10 | .set("Authorization", `Bearer ${token}`) 11 | .send(withdraw); 12 | 13 | return response; 14 | }; 15 | -------------------------------------------------------------------------------- /src/controllers/transaction/summaryTransactions.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { summaryTransactionsAndReturn } from "../../services"; 3 | import { handleError } from "../../error"; 4 | 5 | export default async function summaryTransactions(req: Request, res: Response) { 6 | try { 7 | const summaryValue = await summaryTransactionsAndReturn(req); 8 | 9 | return res.json(summaryValue); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyOutputTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { TransactionWithdrawSchema } from "../../schemas"; 4 | 5 | export default async function verifyOutputTransaction(req: Request, res: Response, next: NextFunction) { 6 | try { 7 | await TransactionWithdrawSchema.validate(req.body); 8 | 9 | next(); 10 | } catch (error: any) { 11 | handleError(res, error, 400); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/services/transaction/insertTransactionAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getToken } from "../../utils"; 3 | import { createNewTransaction } from "../../repositories"; 4 | import { TransactionParams } from "../../models"; 5 | 6 | export default async function insertTransactionAndReturn(params: TransactionParams, req: Request) { 7 | const userId = getToken(req); 8 | 9 | const newTransaction = await createNewTransaction(params, userId); 10 | 11 | return newTransaction; 12 | }; 13 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyTypeofParams.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | 4 | export default function verifyTypeofParams(req: Request, res: Response, next: NextFunction) { 5 | try { 6 | const { id } = req.params; 7 | 8 | if (isNaN(Number(id))) { 9 | throw new Error("invalid value of 'id' parameter"); 10 | } 11 | 12 | next(); 13 | } catch (error: any) { 14 | handleError(res, error, 400); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/services/transaction/getHistoryAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getToken } from "../../utils"; 3 | import { verifyAccountTransactions } from "../../providers"; 4 | import { getTransactions, getTypedTransactions } from "../../repositories"; 5 | 6 | export default async function getHistoryAndReturn(req: Request) { 7 | const id = getToken(req); 8 | 9 | const transactions = await getTransactions(id); 10 | 11 | verifyAccountTransactions(transactions); 12 | 13 | return transactions; 14 | }; 15 | -------------------------------------------------------------------------------- /src/services/user/getUserDetailsAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { getToken } from "../../utils"; 2 | import { Request } from "express"; 3 | import { getUserPerId } from "../../repositories"; 4 | import { undefinedUser } from "../../providers"; 5 | 6 | export default async function getUserDetailsAndReturn(req: Request) { 7 | const userId = getToken(req); 8 | 9 | const user = await getUserPerId(userId); 10 | 11 | undefinedUser(user); 12 | 13 | const { password: _, ...userResponse } = user; 14 | 15 | return userResponse; 16 | }; 17 | -------------------------------------------------------------------------------- /src/repositories/user/refreshUser.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { ReturnedDatabaseUserParams, RefreshUserParams } from "../../models"; 3 | 4 | export default async function refreshUser(params: RefreshUserParams, id: number) { 5 | const newUser: ReturnedDatabaseUserParams[] = await db("users").update({ 6 | email: params.new_email, 7 | password: params.new_password, 8 | phone: params.new_phone 9 | }).where({ id }).returning([ "id", "name", "email" ]); 10 | 11 | return newUser[ 0 ]; 12 | }; 13 | -------------------------------------------------------------------------------- /src/repositories/transaction/getTransaction.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseTransactionParams } from "../../models"; 3 | import { dateFormatter } from "../../utils"; 4 | 5 | export default async function getTransaction(transaction_id: number) { 6 | const transaction: DatabaseTransactionParams = await db("transactions") 7 | .where({ id: transaction_id }).first(); 8 | 9 | if (transaction) { 10 | transaction.date = dateFormatter(transaction.date); 11 | }; 12 | 13 | return transaction; 14 | }; 15 | -------------------------------------------------------------------------------- /src/controllers/transaction/detailTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { getTransactionAndReturn } from "../../services"; 4 | 5 | export default async function detailTransaction(req: Request, res: Response) { 6 | try { 7 | const { id } = req.params; 8 | 9 | const transaction = await getTransactionAndReturn(req, parseInt(id)); 10 | 11 | return res.json(transaction); 12 | } catch (error: any) { 13 | handleError(res, error, 400); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/repositories/user/createNewUser.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { ReturnedDatabaseUserParams, UserParams } from "../../models"; 3 | 4 | export default async function createNewUser(params: UserParams) { 5 | const user: ReturnedDatabaseUserParams[] = await db("users") 6 | .insert({ 7 | name: params.name, 8 | email: params.email, 9 | password: params.password, 10 | cpf: params.cpf, 11 | phone: params.phone 12 | }) 13 | .returning([ "id", "name", "email" ]); 14 | 15 | return user[ 0 ]; 16 | }; 17 | -------------------------------------------------------------------------------- /src/repositories/transaction/getTransactions.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseTransactionParams } from "../../models"; 3 | import { dateFormatter } from "../../utils"; 4 | 5 | export default async function getTransactions(id: number) { 6 | const transactions: DatabaseTransactionParams[] = await db("transactions").where({ user_id: id }); 7 | 8 | if (transactions) { 9 | for (let transaction of transactions) { 10 | transaction.date = dateFormatter(transaction.date); 11 | } 12 | }; 13 | 14 | return transactions; 15 | }; 16 | -------------------------------------------------------------------------------- /src/error/handleError.ts: -------------------------------------------------------------------------------- 1 | import { Response } from "express"; 2 | import HttpStatusError from "./HttpStatusError"; 3 | 4 | export default function handleError(response: Response, error: Error | HttpStatusError, statusCode: number) { 5 | if (error instanceof HttpStatusError) { 6 | response.status(error.statusCode).json({ message: error.message }); 7 | } 8 | else if (error instanceof Error) { 9 | response.status(statusCode).json({ message: error.message }); 10 | } else { 11 | response.status(500).json({ message: "Internal server error" }); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/providers/user/index.ts: -------------------------------------------------------------------------------- 1 | import validateCard from "./validateCard"; 2 | import undefinedUser from "./undefinedUser"; 3 | import verifyEmailExists from "./verifyEmailExists"; 4 | import verifyCpfExists from "./verifyCpfExists"; 5 | import verifyPhoneExists from "./verifyPhoneExists"; 6 | import validateCardType from "./validateCardType"; 7 | import undefinedEmail from "./undefinedEmail"; 8 | 9 | export { 10 | verifyEmailExists, 11 | undefinedUser, 12 | validateCard, 13 | verifyCpfExists, 14 | verifyPhoneExists, 15 | validateCardType, 16 | undefinedEmail 17 | }; 18 | -------------------------------------------------------------------------------- /src/repositories/transaction/getBalancePerId.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | 3 | type Balance = { 4 | balance: number; 5 | } 6 | 7 | export default async function getBalancePerId(userId: number, data: string) { 8 | if (data === "users") { 9 | const { balance }: Balance = await db("users").where({ id: userId }) 10 | .select("balance").first(); 11 | 12 | return balance; 13 | } else { 14 | const { balance }: Balance = await db("credit_cards").where({ user_id: userId }) 15 | .select("balance").first(); 16 | 17 | return balance; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /tests/models/user/CardModels.ts: -------------------------------------------------------------------------------- 1 | import { CardParams } from "../../../src/models"; 2 | 3 | const credit: CardParams = { 4 | "card_number": "1234567812345678", 5 | "cardholder_name": "Victor Navarro", 6 | "expiration_date": "12/31", 7 | "cvv": "123", 8 | "password": "123456", 9 | "card_type": "credit" 10 | }; 11 | 12 | const debit: CardParams = { 13 | "card_number": "8765432187654321", 14 | "cardholder_name": "Victor Navarro", 15 | "expiration_date": "12/31", 16 | "cvv": "123", 17 | "password": "123456", 18 | "card_type": "debit" 19 | }; 20 | 21 | export { credit, debit }; 22 | -------------------------------------------------------------------------------- /src/schemas/user/GeneralCardSchema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from "yup"; 2 | 3 | const GeneralCardSchema = yup.object({ 4 | card_number: yup.string().min(16).max(16).required(), 5 | cardholder_name: yup.string().min(10).max(75).required(), 6 | expiration_date: yup.date().required(), 7 | cvv: yup.string().min(3).max(3).required(), 8 | password: yup.string().min(4).max(6).required(), 9 | new_password: yup.string().min(4).max(6).required(), 10 | card_type: yup.string().min(5).max(6).required(), 11 | value: yup.number().min(0.01).required() 12 | }); 13 | 14 | export default GeneralCardSchema; 15 | -------------------------------------------------------------------------------- /src/schemas/user/GeneralUserSchema.ts: -------------------------------------------------------------------------------- 1 | import * as yup from "yup"; 2 | 3 | const GeneralUserSchema = yup.object({ 4 | name: yup.string().max(75).required(), 5 | email: yup.string().email().max(75).required(), 6 | cpf: yup.string().min(11).max(11).required(), 7 | phone: yup.string().min(10).max(11).required(), 8 | new_phone: yup.string().min(10).max(11).required(), 9 | password: yup.string().min(8).max(16).required(), 10 | new_password: yup.string().min(8).max(16).required(), 11 | new_email: yup.string().email().max(75).required() 12 | }); 13 | 14 | export default GeneralUserSchema; 15 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyType.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | 4 | type Type = { 5 | type: string; 6 | } 7 | 8 | export default function verifyType(req: Request, res: Response, next: NextFunction) { 9 | try { 10 | const { type } = req.body as Type; 11 | 12 | if (type.toLowerCase() !== "input" && type.toLowerCase() !== "output") { 13 | throw new Error("invalid value of 'type'"); 14 | } 15 | 16 | next(); 17 | } catch (error: any) { 18 | handleError(res, error, 400); 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /tests/functions/user/insertUserAndLogin.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../../src/server"; 3 | import { LoginUserParams, UserParams } from "../../../src/models"; 4 | 5 | let bearerToken: string | undefined; 6 | 7 | export default async function insertUserAndLogin(user: UserParams, loginUser: LoginUserParams) { 8 | await request(server) 9 | .post("/user") 10 | .send(user); 11 | 12 | const tokenReq = await request(server) 13 | .post("/login") 14 | .send(loginUser); 15 | 16 | bearerToken = tokenReq.body.token; 17 | 18 | return bearerToken; 19 | }; 20 | -------------------------------------------------------------------------------- /src/middlewares/auth/auth.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { getToken } from "../../utils"; 4 | import { getUserPerId } from "../../repositories"; 5 | import { undefinedUser } from "../../providers"; 6 | 7 | export default async function auth(req: Request, res: Response, next: NextFunction) { 8 | try { 9 | const id = getToken(req); 10 | 11 | const user = await getUserPerId(id); 12 | 13 | undefinedUser(user); 14 | 15 | next(); 16 | } catch (error: any) { 17 | handleError(res, error, 401); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/controllers/user/deleteUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { deleteUserAndConfirm } from "../../services"; 4 | import { DeleteUserParams } from "../../models"; 5 | 6 | export default async function deleteUser(req: Request, res: Response) { 7 | try { 8 | const { password } = req.body as DeleteUserParams; 9 | 10 | await deleteUserAndConfirm(req, password); 11 | 12 | return res.json({ 13 | "message": "your account has been deleted" 14 | }); 15 | } catch (error: any) { 16 | handleError(res, error, 400); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/services/transaction/getTransactionAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getTransaction } from "../../repositories"; 3 | import { getToken } from "../../utils"; 4 | import { validateTransaction, verifyTransactionId } from "../../providers"; 5 | 6 | export default async function getTransactionAndReturn(req: Request, transaction_id: number) { 7 | await verifyTransactionId(transaction_id); 8 | 9 | const userId = getToken(req); 10 | 11 | await validateTransaction(transaction_id, userId); 12 | 13 | const transaction = await getTransaction(transaction_id); 14 | 15 | return transaction; 16 | }; 17 | -------------------------------------------------------------------------------- /src/schemas/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import CardPaySchema from "./CardPaySchema"; 2 | import CardTransactionSchema from "./CardTransactionSchema"; 3 | import DepositSchema from "./DepositSchema"; 4 | import GeneralTransactionSchema from "./GeneralTransactionSchema"; 5 | import PixSchema from "./PixSchema"; 6 | import TransactionSchema from "./TransactionSchema"; 7 | import TransactionWithdrawSchema from "./TransactionWithdrawSchema"; 8 | 9 | export { 10 | TransactionSchema, 11 | GeneralTransactionSchema, 12 | TransactionWithdrawSchema, 13 | DepositSchema, 14 | CardTransactionSchema, 15 | PixSchema, 16 | CardPaySchema 17 | }; 18 | -------------------------------------------------------------------------------- /src/middlewares/transaction/verifyCardTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { CardTransactionSchema } from "../../schemas"; 4 | import { validateCardType } from "../../providers"; 5 | 6 | export default async function verifyCardTransaction(req: Request, res: Response, next: NextFunction) { 7 | try { 8 | await CardTransactionSchema.validate(req.body); 9 | 10 | const { card_type } = req.body; 11 | 12 | validateCardType(card_type); 13 | 14 | next(); 15 | } catch (error: any) { 16 | handleError(res, error, 400); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /src/controllers/user/loginUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { LoginUserParams } from "../../models"; 4 | import { loginUserAndReturn } from "../../services"; 5 | 6 | export default async function loginUser(req: Request, res: Response) { 7 | try { 8 | const { email, password } = req.body as LoginUserParams; 9 | 10 | const params = { 11 | email, 12 | password 13 | }; 14 | 15 | const response = await loginUserAndReturn(params); 16 | 17 | return res.send(response); 18 | } catch (error: any) { 19 | handleError(res, error, 400); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyCardBody.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { CardSchema } from "../../schemas"; 4 | import { validateCardType } from "../../providers"; 5 | import { CardType } from "../../models"; 6 | 7 | export default async function verifyCardBody(req: Request, res: Response, next: NextFunction) { 8 | try { 9 | await CardSchema.validate(req.body); 10 | 11 | const { card_type } = req.body as CardType; 12 | 13 | validateCardType(card_type); 14 | 15 | next(); 16 | } catch (error: any) { 17 | handleError(res, error, 400); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/repositories/transaction/createNewTransaction.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { DatabaseTransactionParams, TransactionParams } from "../../models"; 3 | import { dateFormatter } from "../../utils"; 4 | 5 | export default async function createNewTransaction(params: TransactionParams, user_id: number) { 6 | const newTransaction: DatabaseTransactionParams[] = await db("transactions").insert({ 7 | type: params.type, 8 | description: params.description, 9 | value: params.value, 10 | user_id 11 | }).returning("*"); 12 | 13 | newTransaction[ 0 ].date = dateFormatter(newTransaction[ 0 ].date); 14 | 15 | return newTransaction[ 0 ]; 16 | }; 17 | -------------------------------------------------------------------------------- /src/repositories/transaction/getTypedTransactions.ts: -------------------------------------------------------------------------------- 1 | import { DatabaseTransactionParams } from "../../models"; 2 | 3 | export default function getTypedTransactions(transactions: DatabaseTransactionParams[]) { 4 | const inputTransactions = []; 5 | const outputTransactions = []; 6 | 7 | for (let transaction of transactions) { 8 | if (transaction.type.toLowerCase() === "input") { 9 | inputTransactions.push(transaction); 10 | } 11 | if (transaction.type.toLowerCase() === "output") { 12 | outputTransactions.push(transaction); 13 | } 14 | } 15 | 16 | return { 17 | "input": inputTransactions, 18 | "output": outputTransactions 19 | }; 20 | }; 21 | -------------------------------------------------------------------------------- /src/utils/getToken.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { verify } from "jsonwebtoken"; 3 | import jwtPassword from "../jwt/jwtPassword"; 4 | import { HttpStatusError } from "../error"; 5 | 6 | export default function getToken(req: Request): number { 7 | const { authorization } = req.headers; 8 | 9 | if (!authorization) { 10 | throw new HttpStatusError("unauthorized", 401); 11 | } 12 | 13 | const token = authorization.split(" ")[ 1 ]; 14 | 15 | const userToken = verify(token, jwtPassword); 16 | 17 | if (typeof userToken !== "string") { 18 | return userToken.id; 19 | } else { 20 | throw new HttpStatusError("unauthorized", 401); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/controllers/transaction/makeCardPay.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { makeCardPayAndReturn } from "../../services"; 4 | import { CardPayParams } from "../../models"; 5 | 6 | export default async function makeCardPay(req: Request, res: Response) { 7 | try { 8 | const { value, password } = req.body as CardPayParams; 9 | 10 | const params = { 11 | value, 12 | password 13 | }; 14 | 15 | const transactionResponse = await makeCardPayAndReturn(req, params); 16 | 17 | return res.status(201).json(transactionResponse); 18 | } catch (error: any) { 19 | handleError(res, error, 400); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/middlewares/user/verifyUpdateCardPassword.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateCardPasswordSchema } from "../../schemas"; 4 | import { validateCardType } from "../../providers"; 5 | import { CardType } from "../../models"; 6 | 7 | export default async function verifyUpdateCardPassword(req: Request, res: Response, next: NextFunction) { 8 | try { 9 | await UpdateCardPasswordSchema.validate(req.body); 10 | 11 | const { card_type } = req.body as CardType; 12 | 13 | validateCardType(card_type); 14 | 15 | next(); 16 | } catch (error: any) { 17 | handleError(res, error, 400); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /src/providers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | verifyEmailExists, 3 | undefinedUser, 4 | validateCard, 5 | verifyCpfExists, 6 | verifyPhoneExists, 7 | validateCardType, 8 | undefinedEmail 9 | } from "./user"; 10 | 11 | import { 12 | validateTransaction, 13 | verifyTransactionId, 14 | validatePix, 15 | validateOutput, 16 | verifyAccountTransactions 17 | } from "./transaction"; 18 | 19 | export { 20 | verifyEmailExists, 21 | validateTransaction, 22 | verifyTransactionId, 23 | undefinedUser, 24 | validateCard, 25 | verifyCpfExists, 26 | verifyPhoneExists, 27 | validatePix, 28 | validateOutput, 29 | validateCardType, 30 | verifyAccountTransactions, 31 | undefinedEmail 32 | }; 33 | -------------------------------------------------------------------------------- /src/controllers/transaction/insertPix.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { PixParams } from "../../models"; 4 | import { insertPixAndReturn } from "../../services"; 5 | 6 | export default async function insertPix(req: Request, res: Response) { 7 | try { 8 | const { cpf, password, value } = req.body as PixParams; 9 | 10 | const params = { 11 | cpf, 12 | password, 13 | value 14 | }; 15 | 16 | const responseTransaction = await insertPixAndReturn(req, params); 17 | 18 | return res.status(201).json(responseTransaction); 19 | } catch (error: any) { 20 | handleError(res, error, 400); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/controllers/transaction/makeWithdraw.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { makeWithdrawAndReturn } from "../../services"; 4 | import { WithdrawParams } from "../../models"; 5 | 6 | export default async function makeWithdraw(req: Request, res: Response) { 7 | try { 8 | const { value, password } = req.body as WithdrawParams; 9 | 10 | const params = { 11 | value, 12 | password 13 | }; 14 | 15 | const responseTransaction = await makeWithdrawAndReturn(req, params); 16 | 17 | return res.status(201).json(responseTransaction); 18 | } catch (error: any) { 19 | handleError(res, error, 400); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/services/user/deleteUserAndConfirm.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getToken, validatePassword } from "../../utils"; 3 | import { undefinedUser } from "../../providers"; 4 | import { 5 | dropCards, 6 | dropTransactions, 7 | eraseUser, 8 | getUserPerId 9 | } from "../../repositories"; 10 | 11 | export default async function deleteUserAndConfirm(req: Request, password: string) { 12 | const userId = getToken(req); 13 | 14 | const user = await getUserPerId(userId); 15 | 16 | undefinedUser(user); 17 | 18 | await validatePassword(password, user.password); 19 | 20 | await dropTransactions(userId); 21 | 22 | await dropCards(userId); 23 | 24 | await eraseUser(userId); 25 | }; 26 | -------------------------------------------------------------------------------- /src/controllers/user/insertUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { insertUserAndReturn } from "../../services"; 4 | import { UserParams } from "../../models"; 5 | 6 | export default async function insertUser(req: Request, res: Response) { 7 | try { 8 | const { name, email, password, cpf, phone } = req.body as UserParams; 9 | 10 | const params = { 11 | name, 12 | email, 13 | password, 14 | cpf, 15 | phone 16 | }; 17 | 18 | const user = await insertUserAndReturn(params); 19 | 20 | return res.status(201).json(user); 21 | } catch (error: any) { 22 | handleError(res, error, 400); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/controllers/transaction/insertDeposit.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { insertDepositAndReturn } from "../../services"; 4 | import { DepositParams } from "../../models"; 5 | 6 | export default async function insertDeposit(req: Request, res: Response) { 7 | try { 8 | const { value, email, password } = req.body as DepositParams; 9 | 10 | const params = { 11 | password, 12 | value, 13 | email 14 | }; 15 | 16 | const responseTransaction = await insertDepositAndReturn(req, params); 17 | 18 | return res.status(201).json(responseTransaction); 19 | } catch (error: any) { 20 | handleError(res, error, 400); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/middlewares/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import verifyCardPay from "./verifyCardPay"; 2 | import verifyCardTransaction from "./verifyCardTransaction"; 3 | import verifyDepositTransaction from "./verifyDepositTransaction"; 4 | import verifyOutputTransaction from "./verifyOutputTransaction"; 5 | import verifyPixValue from "./verifyPixValue"; 6 | import verifyTransactionBody from "./verifyTransactionBody"; 7 | import verifyType from "./verifyType"; 8 | import verifyTypeofParams from "./verifyTypeofParams"; 9 | 10 | export { 11 | verifyTransactionBody, 12 | verifyType, 13 | verifyTypeofParams, 14 | verifyOutputTransaction, 15 | verifyDepositTransaction, 16 | verifyCardTransaction, 17 | verifyPixValue, 18 | verifyCardPay 19 | }; 20 | -------------------------------------------------------------------------------- /src/repositories/user/getCardPerUserId.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { HttpStatusError } from "../../error"; 3 | import { dateFormatter } from "../../utils"; 4 | import { 5 | DatabaseCardParams, 6 | GetCardPerUserIdParams 7 | } from "../../models"; 8 | 9 | export default async function getCardPerUserId(params: GetCardPerUserIdParams) { 10 | const card: DatabaseCardParams = await db(params.cardType.toLowerCase() + "_cards") 11 | .where({ user_id: params.userId }).first(); 12 | 13 | if (!card) { 14 | throw new HttpStatusError(`this user not have a ${params.cardType.toLowerCase()} card`, 404); 15 | } 16 | 17 | card.created_at = dateFormatter(card.created_at); 18 | 19 | return card; 20 | }; 21 | -------------------------------------------------------------------------------- /src/services/user/detailCardsAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { getToken } from "../../utils"; 2 | import { Request } from "express"; 3 | import { getCardsPerUserId } from "../../repositories"; 4 | 5 | export default async function detailCardsAndReturn(req: Request) { 6 | const userId = getToken(req); 7 | 8 | const { credit, debit } = await getCardsPerUserId(userId); 9 | 10 | const cards = []; 11 | 12 | if (credit) { 13 | const { password: _, ...creditResponse } = credit; 14 | cards.push({ 15 | credit: creditResponse 16 | }); 17 | } 18 | 19 | if (debit) { 20 | const { password: _, balance: z, ...debitResponse } = debit; 21 | cards.push({ 22 | debit: debitResponse 23 | }); 24 | } 25 | 26 | return cards; 27 | }; 28 | -------------------------------------------------------------------------------- /src/controllers/transaction/insertTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { TransactionParams } from "../../models"; 4 | import { insertTransactionAndReturn } from "../../services"; 5 | 6 | export default async function insertTransaction(req: Request, res: Response) { 7 | try { 8 | const { type, description, value } = req.body as TransactionParams; 9 | 10 | const transaction = { 11 | type, 12 | description, 13 | value 14 | }; 15 | 16 | const newTransaction = await insertTransactionAndReturn(transaction, req); 17 | 18 | return res.status(201).json(newTransaction); 19 | } catch (error: any) { 20 | handleError(res, error, 400); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/controllers/user/updateUserEmail.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateUserEmailParams } from "../../models"; 4 | import { updateEmailAndReturn } from "../../services"; 5 | 6 | export default async function updateUserEmail(req: Request, res: Response) { 7 | try { 8 | const { password, new_email } = req.body as UpdateUserEmailParams; 9 | 10 | const user = { 11 | password, 12 | new_email 13 | }; 14 | 15 | const { email } = await updateEmailAndReturn(req, user); 16 | 17 | res.status(201).json({ 18 | "message": `your email has been changed successfully, now is '${email}'` 19 | }); 20 | } catch (error: any) { 21 | handleError(res, error, 400); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/controllers/user/updateUserPassword.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateUserPasswordParams } from "../../models"; 4 | import { updatePasswordAndConfirm } from "../../services"; 5 | 6 | export default async function updateUserPassword(req: Request, res: Response) { 7 | try { 8 | const { password, new_password } = req.body as UpdateUserPasswordParams; 9 | 10 | const params = { 11 | password, 12 | new_password 13 | }; 14 | 15 | await updatePasswordAndConfirm(req, params); 16 | 17 | return res.status(201).json({ 18 | "message": "your password has been changed successfully" 19 | }); 20 | } catch (error: any) { 21 | handleError(res, error, 400); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/controllers/transaction/insertCardTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { CardTransactionParams } from "../../models"; 4 | import { insertCardTransactionAndReturn } from "../../services"; 5 | 6 | export default async function insertCardTransaction(req: Request, res: Response) { 7 | try { 8 | const { password, card_type, value } = req.body as CardTransactionParams; 9 | 10 | const params = { 11 | password, 12 | card_type, 13 | value 14 | }; 15 | 16 | const responseTransaction = await insertCardTransactionAndReturn(req, params); 17 | 18 | return res.status(201).json(responseTransaction); 19 | } catch (error: any) { 20 | handleError(res, error, 400); 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/controllers/user/updateUserPhone.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { updatePhoneAndReturn } from "../../services"; 4 | import { UpdateUserPhoneParams } from "../../models"; 5 | 6 | export default async function updateUserPhone(req: Request, res: Response) { 7 | try { 8 | const { password, new_phone } = req.body as UpdateUserPhoneParams; 9 | 10 | const params = { 11 | password, 12 | new_phone 13 | }; 14 | 15 | const { phone } = await updatePhoneAndReturn(req, params); 16 | 17 | return res.status(201).json({ 18 | "message": `your phone has been changed successfully, now is '${phone}'` 19 | }); 20 | } catch (error: any) { 21 | handleError(res, error, 400); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/controllers/user/index.ts: -------------------------------------------------------------------------------- 1 | import insertUser from "./insertUser"; 2 | import loginUser from "./loginUser"; 3 | import detailUser from "./detailUser"; 4 | import updateUser from "./updateUser"; 5 | import updateUserEmail from "./updateUserEmail"; 6 | import updateUserPassword from "./updateUserPassword"; 7 | import deleteUser from "./deleteUser"; 8 | import insertCard from "./insertCard"; 9 | import updateCardPassword from "./updateCardPassword"; 10 | import updateUserPhone from "./updateUserPhone"; 11 | import detailCards from "./detailCards"; 12 | 13 | export { 14 | insertUser, 15 | loginUser, 16 | detailUser, 17 | updateUser, 18 | updateUserEmail, 19 | updateUserPassword, 20 | deleteUser, 21 | insertCard, 22 | updateCardPassword, 23 | updateUserPhone, 24 | detailCards 25 | }; 26 | -------------------------------------------------------------------------------- /src/controllers/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import insertTransaction from "./insertTransaction"; 2 | import summaryTransactions from "./summaryTransactions"; 3 | import detailTransaction from "./detailTransaction"; 4 | import deleteTransaction from "./deleteTransaction"; 5 | import insertDeposit from "./insertDeposit"; 6 | import makeWithdraw from "./makeWithdraw"; 7 | import insertCardTransaction from "./insertCardTransaction"; 8 | import insertPix from "./insertPix"; 9 | import makeCardPay from "./makeCardPay"; 10 | import getHistory from "./getHistory"; 11 | 12 | export { 13 | insertTransaction, 14 | summaryTransactions, 15 | detailTransaction, 16 | deleteTransaction, 17 | insertDeposit, 18 | makeWithdraw, 19 | insertCardTransaction, 20 | insertPix, 21 | makeCardPay, 22 | getHistory 23 | }; 24 | -------------------------------------------------------------------------------- /src/services/user/loginUserAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { compare } from "bcrypt"; 2 | import { LoginUserParams } from "../../models"; 3 | import { getUserPerEmail } from "../../repositories"; 4 | import { createToken } from "../../utils"; 5 | import { HttpStatusError } from "../../error"; 6 | 7 | export default async function loginUserAndReturn(params: LoginUserParams) { 8 | const user = await getUserPerEmail(params.email); 9 | 10 | if (!user) { 11 | throw new HttpStatusError("invalid email and/or password", 401); 12 | } 13 | 14 | const validPassword = await compare(params.password, user.password); 15 | 16 | if (!validPassword) { 17 | throw new HttpStatusError("invalid email and/or password", 401); 18 | } 19 | 20 | const response = createToken(user); 21 | 22 | return response; 23 | }; 24 | -------------------------------------------------------------------------------- /src/services/user/updatePasswordAndConfirm.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { UpdateUserPasswordParams } from "../../models"; 3 | import { undefinedUser } from "../../providers"; 4 | import { getUserPerId, refreshUserPassword } from "../../repositories"; 5 | import { 6 | encryptPassword, 7 | getToken, 8 | validatePassword 9 | } from "../../utils"; 10 | 11 | export default async function updatePasswordAndConfirm(req: Request, params: UpdateUserPasswordParams) { 12 | const id = getToken(req); 13 | 14 | const user = await getUserPerId(id); 15 | 16 | undefinedUser(user); 17 | 18 | await validatePassword(params.password, user.password); 19 | 20 | const newPassword = await encryptPassword(params.new_password); 21 | 22 | await refreshUserPassword(id, newPassword); 23 | }; 24 | -------------------------------------------------------------------------------- /src/controllers/user/updateUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { updateUserAndReturn } from "../../services"; 4 | import { UpdateUserParams } from "../../models"; 5 | 6 | export default async function updateUser(req: Request, res: Response) { 7 | try { 8 | const { 9 | password, 10 | new_password, 11 | new_email, 12 | new_phone 13 | } = req.body as UpdateUserParams; 14 | 15 | const params = { 16 | password, 17 | new_password, 18 | new_email, 19 | new_phone 20 | }; 21 | 22 | const newUser = await updateUserAndReturn(req, params); 23 | 24 | return res.status(201).json(newUser); 25 | } catch (error: any) { 26 | handleError(res, error, 400); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/services/user/updateEmailAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { UpdateUserEmailParams } from "../../models"; 3 | import { undefinedUser, verifyEmailExists } from "../../providers"; 4 | import { getUserPerId, refreshUserEmail } from "../../repositories"; 5 | import { getToken, validatePassword } from "../../utils"; 6 | 7 | export default async function updateEmailAndReturn(req: Request, params: UpdateUserEmailParams) { 8 | await verifyEmailExists(params.new_email); 9 | 10 | const userId = getToken(req); 11 | 12 | const user = await getUserPerId(userId); 13 | 14 | undefinedUser(user); 15 | 16 | await validatePassword(params.password, user.password); 17 | 18 | const returnedEmail = await refreshUserEmail(userId, params.new_email); 19 | 20 | return returnedEmail; 21 | }; 22 | -------------------------------------------------------------------------------- /src/services/user/updatePhoneAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { UpdateUserPhoneParams } from "../../models"; 3 | import { getToken, validatePassword } from "../../utils"; 4 | import { getUserPerId, refreshUserPhone } from "../../repositories"; 5 | import { undefinedUser, verifyPhoneExists } from "../../providers"; 6 | 7 | export default async function updatePhoneAndReturn(req: Request, params: UpdateUserPhoneParams) { 8 | const id = getToken(req); 9 | 10 | const user = await getUserPerId(id); 11 | 12 | undefinedUser(user); 13 | 14 | await validatePassword(params.password, user.password); 15 | 16 | await verifyPhoneExists(params.new_phone); 17 | 18 | const returnedPhone = await refreshUserPhone(user.phone, params.new_phone); 19 | 20 | return returnedPhone; 21 | }; 22 | -------------------------------------------------------------------------------- /src/controllers/transaction/deleteTransaction.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { deleteTransactionAndConfirm } from "../../services"; 4 | import { DeleteTransactionParams } from "../../models"; 5 | 6 | export default async function deleteTransaction(req: Request, res: Response) { 7 | try { 8 | const { id } = req.params; 9 | const { password } = req.body as DeleteTransactionParams; 10 | 11 | const params = { 12 | transaction_id: parseInt(id), 13 | password: password 14 | }; 15 | 16 | await deleteTransactionAndConfirm(req, params); 17 | 18 | return res.json({ 19 | message: "your transaction has been deleted successfully" 20 | }); 21 | } catch (error: any) { 22 | handleError(res, error, 400); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/controllers/user/updateCardPassword.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { UpdateCardPasswordParams } from "../../models"; 4 | import { updateCardPasswordAndConfirm } from "../../services"; 5 | 6 | export default async function updateCardPassword(req: Request, res: Response) { 7 | try { 8 | const { card_type, password, new_password } = req.body as UpdateCardPasswordParams; 9 | 10 | const params = { 11 | card_type, 12 | password, 13 | new_password 14 | }; 15 | 16 | await updateCardPasswordAndConfirm(req, params); 17 | 18 | return res.status(201).json({ 19 | message: `password of your ${card_type.toLowerCase()} card has been updated successfully` 20 | }); 21 | } catch (error: any) { 22 | handleError(res, error, 400); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/services/transaction/summaryTransactionsAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getToken } from "../../utils"; 3 | import { getTypedTransactions } from "../../repositories"; 4 | import { verifyAccountTransactions } from "../../providers"; 5 | import { getTransactions, getTypeValue } from "../../repositories"; 6 | 7 | export default async function summaryTransactionsAndReturn(req: Request) { 8 | const id = getToken(req); 9 | 10 | const transactions = await getTransactions(id); 11 | 12 | verifyAccountTransactions(transactions); 13 | 14 | const typedTransactions = getTypedTransactions(transactions); 15 | 16 | const outputValue = getTypeValue(typedTransactions.output); 17 | 18 | const inputValue = getTypeValue(typedTransactions.input); 19 | 20 | return { 21 | input: inputValue, 22 | output: outputValue 23 | }; 24 | }; 25 | -------------------------------------------------------------------------------- /src/middlewares/user/index.ts: -------------------------------------------------------------------------------- 1 | import verifyUserBody from "./verifyUserBody"; 2 | import verifyLoginUserBody from "./verifyLoginUserBody"; 3 | import verifyUpdateEmailUserBody from "./verifyUpdateEmailUserBody"; 4 | import verifyUpdateUserBody from "./verifyUpdateUserBody"; 5 | import verifyUpdatePasswordUserBody from "./verifyUpdatePasswordUserBody"; 6 | import verifyPassword from "./verifyPassword"; 7 | import verifyCardBody from "./verifyCardBody"; 8 | import verifyUpdateCardPassword from "./verifyUpdateCardPassword"; 9 | import verifyUpdatePhoneUserBody from "./verifyUpdatePhoneUser"; 10 | 11 | export { 12 | verifyUserBody, 13 | verifyLoginUserBody, 14 | verifyUpdateEmailUserBody, 15 | verifyUpdateUserBody, 16 | verifyUpdatePasswordUserBody, 17 | verifyPassword, 18 | verifyCardBody, 19 | verifyUpdateCardPassword, 20 | verifyUpdatePhoneUserBody 21 | }; 22 | -------------------------------------------------------------------------------- /src/services/user/insertUserAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { UserParams } from "../../models"; 2 | import { createNewUser } from "../../repositories"; 3 | import { encryptPassword } from "../../utils"; 4 | import { 5 | verifyCpfExists, 6 | verifyEmailExists, 7 | verifyPhoneExists 8 | } from "../../providers"; 9 | 10 | export default async function insertUserAndReturn(params: UserParams) { 11 | await verifyEmailExists(params.email); 12 | 13 | await verifyCpfExists(params.cpf); 14 | 15 | await verifyPhoneExists(params.phone); 16 | 17 | const cryptPassword = await encryptPassword(params.password); 18 | 19 | const newUser = { 20 | name: params.name, 21 | email: params.email, 22 | password: cryptPassword, 23 | cpf: params.cpf, 24 | phone: params.phone 25 | }; 26 | 27 | const user = await createNewUser(newUser); 28 | 29 | return user; 30 | }; 31 | -------------------------------------------------------------------------------- /src/services/transaction/deleteTransactionAndConfirm.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { dropTransaction, getUserPerId } from "../../repositories"; 3 | import { DeleteTransactionParams } from "../../models"; 4 | import { getToken, validatePassword } from "../../utils"; 5 | import { 6 | undefinedUser, 7 | validateTransaction, 8 | verifyTransactionId 9 | } from "../../providers"; 10 | 11 | export default async function deleteTransactionAndConfirm(req: Request, params: DeleteTransactionParams) { 12 | await verifyTransactionId(params.transaction_id); 13 | 14 | const userId = getToken(req); 15 | 16 | const user = await getUserPerId(userId); 17 | 18 | undefinedUser(user); 19 | 20 | await validatePassword(params.password, user.password); 21 | 22 | await validateTransaction(params.transaction_id, userId); 23 | 24 | await dropTransaction(params.transaction_id); 25 | }; 26 | -------------------------------------------------------------------------------- /src/schemas/user/index.ts: -------------------------------------------------------------------------------- 1 | import UserSchema from "./UserSchema"; 2 | import LoginUserSchema from "./LoginUserSchema"; 3 | import GeneralUserSchema from "./GeneralUserSchema"; 4 | import UpdateEmailSchema from "./UpdateEmailSchema"; 5 | import UpdatePasswordSchema from "./UpdatePasswordSchema"; 6 | import UpdateUserSchema from "./UpdateUserSchema"; 7 | import PasswordSchema from "./PasswordSchema"; 8 | import CardSchema from "./CardSchema"; 9 | import GeneralCardSchema from "./GeneralCardSchema"; 10 | import UpdateCardPasswordSchema from "./UpdateCardPasswordSchema"; 11 | import UpdatePhoneSchema from "./UpdatePhoneSchema"; 12 | 13 | export { 14 | UserSchema, 15 | LoginUserSchema, 16 | GeneralUserSchema, 17 | UpdateEmailSchema, 18 | UpdatePasswordSchema, 19 | UpdateUserSchema, 20 | PasswordSchema, 21 | GeneralCardSchema, 22 | CardSchema, 23 | UpdateCardPasswordSchema, 24 | UpdatePhoneSchema 25 | }; 26 | -------------------------------------------------------------------------------- /src/providers/user/validateCard.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { HttpStatusError } from "../../error"; 3 | import { DatabaseCardParams, ValidateCardParams } from "../../models"; 4 | 5 | export default async function validateCard(params: ValidateCardParams) { 6 | const userHaveCard: DatabaseCardParams[] = await db(params.card_type.toLowerCase() + "_cards") 7 | .where({ 8 | user_id: params.user_id 9 | }); 10 | 11 | if (userHaveCard.length > 0) { 12 | throw new HttpStatusError(`this user already have a ${params.card_type.toLowerCase()} card`, 409); 13 | } 14 | 15 | const cardExists: DatabaseCardParams[] = await db(params.card_type.toLowerCase() + "_cards") 16 | .where({ 17 | "card_number": params.card_number 18 | }); 19 | 20 | if (cardExists.length > 0) { 21 | throw new HttpStatusError(`this ${params.card_type} card already used per other user`, 409); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/services/user/updateCardPasswordAndConfirm.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { UpdateCardPasswordParams } from "../../models"; 3 | import { getCardPerUserId, refreshCardPassword } from "../../repositories"; 4 | import { 5 | encryptPassword, 6 | getToken, 7 | validatePassword 8 | } from "../../utils"; 9 | 10 | export default async function updateCardPasswordAndConfirm(req: Request, params: UpdateCardPasswordParams) { 11 | const userId = getToken(req); 12 | 13 | const cardParams = { 14 | cardType: params.card_type, 15 | userId 16 | }; 17 | 18 | const card = await getCardPerUserId(cardParams); 19 | 20 | await validatePassword(params.password, card.password); 21 | 22 | const password = await encryptPassword(params.new_password); 23 | 24 | const refreshParams = { 25 | card_id: card.id, 26 | card_type: params.card_type, 27 | new_password: password 28 | }; 29 | 30 | await refreshCardPassword(refreshParams); 31 | }; 32 | -------------------------------------------------------------------------------- /src/schemas/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | UserSchema, 3 | LoginUserSchema, 4 | GeneralUserSchema, 5 | UpdateEmailSchema, 6 | UpdatePasswordSchema, 7 | UpdateUserSchema, 8 | PasswordSchema, 9 | GeneralCardSchema, 10 | CardSchema, 11 | UpdateCardPasswordSchema, 12 | UpdatePhoneSchema 13 | } from "./user"; 14 | 15 | import { 16 | TransactionSchema, 17 | GeneralTransactionSchema, 18 | TransactionWithdrawSchema, 19 | DepositSchema, 20 | CardTransactionSchema, 21 | PixSchema, 22 | CardPaySchema 23 | } from "./transaction"; 24 | 25 | export { 26 | UserSchema, 27 | LoginUserSchema, 28 | TransactionSchema, 29 | GeneralUserSchema, 30 | UpdateEmailSchema, 31 | UpdatePasswordSchema, 32 | UpdateUserSchema, 33 | PasswordSchema, 34 | GeneralTransactionSchema, 35 | TransactionWithdrawSchema, 36 | GeneralCardSchema, 37 | CardSchema, 38 | DepositSchema, 39 | CardTransactionSchema, 40 | UpdateCardPasswordSchema, 41 | UpdatePhoneSchema, 42 | PixSchema, 43 | CardPaySchema 44 | }; 45 | -------------------------------------------------------------------------------- /src/controllers/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | insertUser, 3 | loginUser, 4 | detailUser, 5 | updateUser, 6 | updateUserEmail, 7 | updateUserPassword, 8 | deleteUser, 9 | insertCard, 10 | updateCardPassword, 11 | updateUserPhone, 12 | detailCards 13 | } from "./user"; 14 | 15 | import { 16 | insertTransaction, 17 | summaryTransactions, 18 | detailTransaction, 19 | deleteTransaction, 20 | insertDeposit, 21 | makeWithdraw, 22 | insertCardTransaction, 23 | insertPix, 24 | makeCardPay, 25 | getHistory 26 | } from "./transaction"; 27 | 28 | export { 29 | insertUser, 30 | loginUser, 31 | detailUser, 32 | updateUser, 33 | insertTransaction, 34 | summaryTransactions, 35 | detailTransaction, 36 | deleteTransaction, 37 | updateUserEmail, 38 | updateUserPassword, 39 | deleteUser, 40 | insertDeposit, 41 | makeWithdraw, 42 | insertCard, 43 | insertCardTransaction, 44 | updateCardPassword, 45 | updateUserPhone, 46 | insertPix, 47 | makeCardPay, 48 | getHistory, 49 | detailCards 50 | }; 51 | -------------------------------------------------------------------------------- /src/services/transaction/makeWithdrawAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { WithdrawParams } from "../../models"; 3 | import { getToken, validatePassword } from "../../utils"; 4 | import { undefinedUser, validateOutput } from "../../providers"; 5 | import { 6 | createNewTransaction, 7 | getUserPerId, 8 | removeValue 9 | } from "../../repositories"; 10 | 11 | export default async function makeWithdrawAndReturn(req: Request, params: WithdrawParams) { 12 | const userId = getToken(req); 13 | 14 | const user = await getUserPerId(userId); 15 | 16 | undefinedUser(user); 17 | 18 | await validatePassword(params.password, user.password); 19 | 20 | validateOutput(user.balance, params.value); 21 | 22 | await removeValue("balance", params.value, userId); 23 | 24 | const transaction = { 25 | type: "output", 26 | description: "withdraw", 27 | value: params.value 28 | }; 29 | 30 | const responseTransaction = await createNewTransaction(transaction, userId); 31 | 32 | return responseTransaction; 33 | }; 34 | -------------------------------------------------------------------------------- /src/services/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import summaryTransactionsAndReturn from "./summaryTransactionsAndReturn"; 2 | import insertTransactionAndReturn from "./insertTransactionAndReturn"; 3 | import getTransactionAndReturn from "./getTransactionAndReturn"; 4 | import deleteTransactionAndConfirm from "./deleteTransactionAndConfirm"; 5 | import insertDepositAndReturn from "./insertDepositAndReturn"; 6 | import makeWithdrawAndReturn from "./makeWithdrawAndReturn"; 7 | import insertCardTransactionAndReturn from "./insertCardTransactionAndReturn"; 8 | import insertPixAndReturn from "./insertPixAndReturn"; 9 | import makeCardPayAndReturn from "./makeCardPayAndReturn"; 10 | import getHistoryAndReturn from "./getHistoryAndReturn"; 11 | 12 | export { 13 | insertTransactionAndReturn, 14 | summaryTransactionsAndReturn, 15 | getTransactionAndReturn, 16 | deleteTransactionAndConfirm, 17 | insertDepositAndReturn, 18 | makeWithdrawAndReturn, 19 | insertCardTransactionAndReturn, 20 | insertPixAndReturn, 21 | makeCardPayAndReturn, 22 | getHistoryAndReturn 23 | }; 24 | -------------------------------------------------------------------------------- /src/models/transaction/index.ts: -------------------------------------------------------------------------------- 1 | import { CardPayParams } from "./CardPayParams"; 2 | import { CardTransactionParams } from "./CardTransactionParams"; 3 | import { CardType } from "./CardType"; 4 | import { DatabaseTransactionParams } from "./DatabaseTransactionParams"; 5 | import { DeleteTransactionParams } from "./DeleteTransactionParams"; 6 | import { DepositParams } from "./DepositParams"; 7 | import { GetCardPerUserIdParams } from "./GetCardPerUserIdParams"; 8 | import { NewPixParams } from "./NewPixParams"; 9 | import { OutputTransactionParams } from "./OutputTransactionParams"; 10 | import { PixParams } from "./PixParams"; 11 | import { TransactionParams } from "./TransactionParams"; 12 | import { WithdrawParams } from "./WithdrawParams"; 13 | 14 | export { 15 | TransactionParams, 16 | DatabaseTransactionParams, 17 | DeleteTransactionParams, 18 | OutputTransactionParams, 19 | CardTransactionParams, 20 | PixParams, 21 | DepositParams, 22 | CardPayParams, 23 | NewPixParams, 24 | GetCardPerUserIdParams, 25 | WithdrawParams, 26 | CardType 27 | }; 28 | -------------------------------------------------------------------------------- /src/services/user/index.ts: -------------------------------------------------------------------------------- 1 | import insertUserAndReturn from "./insertUserAndReturn"; 2 | import loginUserAndReturn from "./loginUserAndReturn"; 3 | import getUserDetailsAndReturn from "./getUserDetailsAndReturn"; 4 | import updateUserAndReturn from "./updateUserAndReturn"; 5 | import updateEmailAndReturn from "./updateEmailAndReturn"; 6 | import updatePasswordAndConfirm from "./updatePasswordAndConfirm"; 7 | import deleteUserAndConfirm from "./deleteUserAndConfirm"; 8 | import insertCardAndReturn from "./insertCardAndReturn"; 9 | import updateCardPasswordAndConfirm from "./updateCardPasswordAndConfirm"; 10 | import updatePhoneAndReturn from "./updatePhoneAndReturn"; 11 | import detailCardsAndReturn from "./detailCardsAndReturn"; 12 | 13 | export { 14 | insertUserAndReturn, 15 | loginUserAndReturn, 16 | getUserDetailsAndReturn, 17 | updateUserAndReturn, 18 | updateEmailAndReturn, 19 | updatePasswordAndConfirm, 20 | deleteUserAndConfirm, 21 | insertCardAndReturn, 22 | updateCardPasswordAndConfirm, 23 | updatePhoneAndReturn, 24 | detailCardsAndReturn 25 | }; 26 | -------------------------------------------------------------------------------- /src/repositories/user/index.ts: -------------------------------------------------------------------------------- 1 | import createNewUser from "./createNewUser"; 2 | import getUserPerEmail from "./getUserPerEmail"; 3 | import getUserPerId from "./getUserPerId"; 4 | import refreshUser from "./refreshUser"; 5 | import refreshUserEmail from "./refreshUserEmail"; 6 | import refreshUserPassword from "./refreshUserPassword"; 7 | import eraseUser from "./eraseUser"; 8 | import createCard from "./createCard"; 9 | import getCardPerUserId from "./getCardPerUserId"; 10 | import getUserPerCpf from "./getUserPerCpf"; 11 | import refreshCardPassword from "./refreshCardPassword"; 12 | import getUserPerPhone from "./getUserPerPhone"; 13 | import refreshUserPhone from "./refreshUserPhone"; 14 | import getCardsPerUserId from "./getCardsPerUserId"; 15 | 16 | export { 17 | createNewUser, 18 | getUserPerEmail, 19 | getUserPerId, 20 | refreshUser, 21 | refreshUserEmail, 22 | refreshUserPassword, 23 | eraseUser, 24 | createCard, 25 | getCardPerUserId, 26 | getUserPerCpf, 27 | refreshCardPassword, 28 | getUserPerPhone, 29 | refreshUserPhone, 30 | getCardsPerUserId 31 | }; 32 | -------------------------------------------------------------------------------- /src/repositories/user/getCardsPerUserId.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { HttpStatusError } from "../../error"; 3 | import { DatabaseCardParams } from "../../models"; 4 | import { dateFormatter } from "../../utils"; 5 | 6 | type responseCards = { 7 | credit: DatabaseCardParams; 8 | debit: DatabaseCardParams; 9 | } 10 | 11 | export default async function getCardsPerUserId(user_id: number) { 12 | const credit: DatabaseCardParams = await db("credit_cards") 13 | .where({ user_id }).first(); 14 | 15 | const debit: DatabaseCardParams = await db("debit_cards") 16 | .where({ user_id }).first(); 17 | 18 | if (!credit && !debit) { 19 | throw new HttpStatusError("this user does not have a card", 404); 20 | } 21 | 22 | if (typeof credit !== "undefined") { 23 | credit.created_at = dateFormatter(credit.created_at); 24 | } 25 | 26 | if (typeof debit !== "undefined") { 27 | debit.created_at = dateFormatter(debit.created_at); 28 | } 29 | 30 | const cards: responseCards = { 31 | credit, 32 | debit 33 | }; 34 | 35 | return cards; 36 | }; 37 | -------------------------------------------------------------------------------- /src/middlewares/index.ts: -------------------------------------------------------------------------------- 1 | import auth from "./auth"; 2 | 3 | import { 4 | verifyUserBody, 5 | verifyLoginUserBody, 6 | verifyUpdateEmailUserBody, 7 | verifyUpdateUserBody, 8 | verifyUpdatePasswordUserBody, 9 | verifyCardBody, 10 | verifyPassword, 11 | verifyUpdateCardPassword, 12 | verifyUpdatePhoneUserBody 13 | } from "./user"; 14 | 15 | import { 16 | verifyTransactionBody, 17 | verifyType, 18 | verifyTypeofParams, 19 | verifyOutputTransaction, 20 | verifyDepositTransaction, 21 | verifyCardTransaction, 22 | verifyPixValue, 23 | verifyCardPay 24 | } from "./transaction"; 25 | 26 | export { 27 | verifyUserBody, 28 | verifyLoginUserBody, 29 | auth, 30 | verifyTransactionBody, 31 | verifyType, 32 | verifyTypeofParams, 33 | verifyUpdateEmailUserBody, 34 | verifyUpdateUserBody, 35 | verifyUpdatePasswordUserBody, 36 | verifyPassword, 37 | verifyOutputTransaction, 38 | verifyCardBody, 39 | verifyDepositTransaction, 40 | verifyCardTransaction, 41 | verifyUpdateCardPassword, 42 | verifyUpdatePhoneUserBody, 43 | verifyPixValue, 44 | verifyCardPay 45 | }; 46 | -------------------------------------------------------------------------------- /src/repositories/user/createCard.ts: -------------------------------------------------------------------------------- 1 | import db from "../../data/connection"; 2 | import { InsertCardParams } from "../../models"; 3 | 4 | type Balance = { 5 | balance: number 6 | } 7 | 8 | export default async function createCard(params: InsertCardParams) { 9 | if (params.card_type.toLowerCase() === "credit") { 10 | const value: Balance[] = await db("credit_cards").insert({ 11 | card_number: params.card_number, 12 | cardholder_name: params.cardholder_name, 13 | expiration_date: params.expiration_date, 14 | cvv: params.cvv, 15 | user_id: params.user_id, 16 | balance: params.balance, 17 | password: params.password 18 | }).returning("balance"); 19 | 20 | return value[ 0 ].balance; 21 | } else if (params.card_type.toLowerCase() === "debit") { 22 | await db("debit_cards").insert({ 23 | card_number: params.card_number, 24 | cardholder_name: params.cardholder_name, 25 | expiration_date: params.expiration_date, 26 | cvv: params.cvv, 27 | user_id: params.user_id, 28 | password: params.password 29 | }); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/services/user/updateUserAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { getToken } from "../../utils"; 3 | import { UpdateUserParams } from "../../models"; 4 | import { getUserPerId, refreshUser } from "../../repositories"; 5 | import { encryptPassword, validatePassword } from "../../utils"; 6 | import { 7 | undefinedUser, 8 | verifyEmailExists, 9 | verifyPhoneExists 10 | } from "../../providers"; 11 | 12 | export default async function updateUserAndReturn(req: Request, params: UpdateUserParams) { 13 | await verifyEmailExists(params.new_email); 14 | 15 | await verifyPhoneExists(params.new_phone); 16 | 17 | const userId = getToken(req); 18 | 19 | const user = await getUserPerId(userId); 20 | 21 | undefinedUser(user); 22 | 23 | await validatePassword(params.password, user.password); 24 | 25 | const cryptPassword = await encryptPassword(params.new_password); 26 | 27 | const refreshed = { 28 | new_email: params.new_email, 29 | new_password: cryptPassword, 30 | new_phone: params.new_phone 31 | }; 32 | 33 | const newUser = await refreshUser(refreshed, userId); 34 | 35 | return newUser; 36 | }; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Victor José Lopes Navarro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/repositories/transaction/index.ts: -------------------------------------------------------------------------------- 1 | 2 | import getCategoriePerId from "./getCategoriePerId"; 3 | import createNewTransaction from "./createNewTransaction"; 4 | import getTransactions from "./getTransactions"; 5 | import getTransaction from "./getTransaction"; 6 | import dropTransaction from "./dropTransaction"; 7 | import createNewDeposit from "./createNewDeposit"; 8 | import removeValue from "./removeValue"; 9 | import getBalancePerId from "./getBalancePerId"; 10 | import createCardTransaction from "./createCardTransaction"; 11 | import createNewPix from "./createNewPix"; 12 | import cardPay from "./cardPay"; 13 | import getTypedTransactions from "./getTypedTransactions"; 14 | import getTypeValue from "./getTypeValue"; 15 | import dropTransactions from "./dropTransactions"; 16 | import dropCards from "./dropCards"; 17 | 18 | export { 19 | getCategoriePerId, 20 | createNewTransaction, 21 | getTransactions, 22 | getTransaction, 23 | dropTransaction, 24 | createNewDeposit, 25 | removeValue, 26 | getBalancePerId, 27 | createCardTransaction, 28 | createNewPix, 29 | cardPay, 30 | getTypedTransactions, 31 | getTypeValue, 32 | dropTransactions, 33 | dropCards 34 | }; 35 | -------------------------------------------------------------------------------- /src/services/user/insertCardAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { CardParams } from "../../models"; 3 | import { validateCard } from "../../providers"; 4 | import { encryptPassword, getToken } from "../../utils"; 5 | import { createCard, getBalancePerId } from "../../repositories"; 6 | 7 | export default async function insertCardAndReturn(req: Request, params: CardParams) { 8 | const user_id = getToken(req); 9 | 10 | const validateParams = { 11 | card_type: params.card_type, 12 | user_id, 13 | "card_number": params.card_number 14 | }; 15 | 16 | await validateCard(validateParams); 17 | 18 | const balance = await getBalancePerId(user_id, "users"); 19 | 20 | const cardPassword = await encryptPassword(params.password); 21 | 22 | const createCardParams = { 23 | card_number: params.card_number, 24 | cardholder_name: params.cardholder_name, 25 | expiration_date: params.expiration_date, 26 | cvv: params.cvv, 27 | user_id, 28 | balance, 29 | password: cardPassword, 30 | card_type: params.card_type 31 | }; 32 | 33 | const responseBalance = await createCard(createCardParams); 34 | 35 | return responseBalance; 36 | }; 37 | -------------------------------------------------------------------------------- /src/controllers/user/insertCard.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { handleError } from "../../error"; 3 | import { insertCardAndReturn } from "../../services"; 4 | import { CardParams } from "../../models"; 5 | 6 | export default async function insertCard(req: Request, res: Response) { 7 | try { 8 | const { 9 | card_number, 10 | cardholder_name, 11 | expiration_date, 12 | cvv, 13 | password, 14 | card_type 15 | } = req.body as CardParams; 16 | 17 | const params = { 18 | card_number, 19 | cardholder_name, 20 | expiration_date, 21 | cvv, 22 | password, 23 | card_type 24 | }; 25 | 26 | const balance = await insertCardAndReturn(req, params); 27 | 28 | if (typeof balance === "number" && balance >= 0) { 29 | return res.status(201).json({ 30 | message: `${card_type.toLowerCase()} card added successfully. Your credit limit is: ${balance}` 31 | }); 32 | } else { 33 | return res.status(201).json({ 34 | message: `${card_type.toLowerCase()} card added successfully` 35 | }); 36 | } 37 | } catch (error: any) { 38 | handleError(res, error, 400); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /src/services/transaction/insertDepositAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { HttpStatusError } from "../../error"; 3 | import { DepositParams } from "../../models"; 4 | import { getToken, validatePassword } from "../../utils"; 5 | import { undefinedUser } from "../../providers"; 6 | import { 7 | createNewDeposit, 8 | createNewTransaction, 9 | getUserPerId, 10 | getUserPerEmail 11 | } from "../../repositories"; 12 | 13 | export default async function insertDepositAndReturn(req: Request, params: DepositParams) { 14 | const validEmail = await getUserPerEmail(params.email); 15 | 16 | if (!validEmail) { 17 | throw new HttpStatusError("email not found", 404); 18 | } 19 | 20 | const userId = getToken(req); 21 | 22 | const user = await getUserPerId(userId); 23 | 24 | undefinedUser(user); 25 | 26 | await validatePassword(params.password, user.password); 27 | 28 | await createNewDeposit(params.email, params.value); 29 | 30 | let transactionParams = { 31 | type: "input", 32 | description: "deposit", 33 | value: params.value 34 | }; 35 | 36 | const inputTransaction = await createNewTransaction(transactionParams, validEmail.id); 37 | 38 | return inputTransaction; 39 | }; 40 | -------------------------------------------------------------------------------- /src/services/transaction/makeCardPayAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { OutputTransactionParams } from "../../models"; 3 | import { getToken, validatePassword } from "../../utils"; 4 | import { undefinedUser, validateOutput } from "../../providers"; 5 | import { 6 | cardPay, 7 | createNewTransaction, 8 | getCardPerUserId, 9 | getUserPerId, 10 | removeValue 11 | } from "../../repositories"; 12 | 13 | export default async function makeCardPayAndReturn(req: Request, params: OutputTransactionParams) { 14 | const userId = getToken(req); 15 | 16 | const user = await getUserPerId(userId); 17 | 18 | undefinedUser(user); 19 | 20 | await validatePassword(params.password, user.password); 21 | 22 | const getCard = { 23 | cardType: "credit", 24 | userId 25 | }; 26 | 27 | await getCardPerUserId(getCard); 28 | 29 | validateOutput(user.balance, params.value); 30 | 31 | await cardPay(params.value, userId); 32 | 33 | await removeValue("balance", params.value, userId); 34 | 35 | const transaction = { 36 | type: "output", 37 | description: "card pay", 38 | value: params.value 39 | }; 40 | 41 | const transactionResponse = await createNewTransaction(transaction, userId); 42 | 43 | return transactionResponse; 44 | }; 45 | -------------------------------------------------------------------------------- /src/services/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | insertUserAndReturn, 3 | loginUserAndReturn, 4 | getUserDetailsAndReturn, 5 | updateUserAndReturn, 6 | updateEmailAndReturn, 7 | updatePasswordAndConfirm, 8 | deleteUserAndConfirm, 9 | insertCardAndReturn, 10 | updateCardPasswordAndConfirm, 11 | updatePhoneAndReturn, 12 | detailCardsAndReturn 13 | } from "./user"; 14 | 15 | import { 16 | insertTransactionAndReturn, 17 | summaryTransactionsAndReturn, 18 | getTransactionAndReturn, 19 | deleteTransactionAndConfirm, 20 | insertDepositAndReturn, 21 | makeWithdrawAndReturn, 22 | insertCardTransactionAndReturn, 23 | insertPixAndReturn, 24 | makeCardPayAndReturn, 25 | getHistoryAndReturn 26 | } from "./transaction"; 27 | 28 | export { 29 | insertUserAndReturn, 30 | loginUserAndReturn, 31 | getUserDetailsAndReturn, 32 | updateUserAndReturn, 33 | insertTransactionAndReturn, 34 | summaryTransactionsAndReturn, 35 | getTransactionAndReturn, 36 | deleteTransactionAndConfirm, 37 | updateEmailAndReturn, 38 | updatePasswordAndConfirm, 39 | deleteUserAndConfirm, 40 | insertDepositAndReturn, 41 | makeWithdrawAndReturn, 42 | insertCardAndReturn, 43 | insertCardTransactionAndReturn, 44 | updateCardPasswordAndConfirm, 45 | updatePhoneAndReturn, 46 | insertPixAndReturn, 47 | makeCardPayAndReturn, 48 | getHistoryAndReturn, 49 | detailCardsAndReturn 50 | }; 51 | -------------------------------------------------------------------------------- /src/services/transaction/insertCardTransactionAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { CardTransactionParams } from "../../models"; 3 | import { getToken, validatePassword } from "../../utils"; 4 | import { undefinedUser, validateOutput } from "../../providers"; 5 | import { 6 | createCardTransaction, 7 | createNewTransaction, 8 | getCardPerUserId, 9 | getUserPerId 10 | } from "../../repositories"; 11 | 12 | export default async function insertCardTransactionAndReturn(req: Request, params: CardTransactionParams) { 13 | const userId = getToken(req); 14 | 15 | const cardParams = { 16 | cardType: params.card_type, 17 | userId 18 | }; 19 | 20 | const card = await getCardPerUserId(cardParams); 21 | 22 | await validatePassword(params.password, card.password); 23 | 24 | if (typeof card.balance === "undefined") { 25 | const user = await getUserPerId(userId); 26 | 27 | undefinedUser(user); 28 | 29 | validateOutput(user.balance, params.value); 30 | } else { 31 | validateOutput(card.balance, params.value); 32 | } 33 | 34 | await createCardTransaction(params.card_type, userId, params.value); 35 | 36 | const transactionParams = { 37 | type: "output", 38 | description: params.card_type.toLowerCase(), 39 | value: params.value 40 | }; 41 | 42 | const responseTransaction = await createNewTransaction(transactionParams, userId); 43 | 44 | return responseTransaction; 45 | }; 46 | -------------------------------------------------------------------------------- /src/repositories/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createNewUser, 3 | getUserPerEmail, 4 | getUserPerId, 5 | refreshUser, 6 | refreshUserEmail, 7 | refreshUserPassword, 8 | eraseUser, 9 | createCard, 10 | getCardPerUserId, 11 | getUserPerCpf, 12 | refreshCardPassword, 13 | getUserPerPhone, 14 | refreshUserPhone, 15 | getCardsPerUserId 16 | } from "./user"; 17 | 18 | import { 19 | getCategoriePerId, 20 | createNewTransaction, 21 | getTransactions, 22 | getTransaction, 23 | dropTransaction, 24 | createNewDeposit, 25 | removeValue, 26 | getBalancePerId, 27 | createCardTransaction, 28 | createNewPix, 29 | cardPay, 30 | getTypedTransactions, 31 | getTypeValue, 32 | dropTransactions, 33 | dropCards 34 | } from "./transaction"; 35 | 36 | export { 37 | createNewUser, 38 | getUserPerEmail, 39 | getUserPerId, 40 | refreshUser, 41 | getCategoriePerId, 42 | createNewTransaction, 43 | getTransactions, 44 | getTransaction, 45 | dropTransaction, 46 | refreshUserEmail, 47 | refreshUserPassword, 48 | eraseUser, 49 | createNewDeposit, 50 | getBalancePerId, 51 | removeValue, 52 | createCard, 53 | getCardPerUserId, 54 | createCardTransaction, 55 | getUserPerCpf, 56 | refreshCardPassword, 57 | getUserPerPhone, 58 | refreshUserPhone, 59 | createNewPix, 60 | cardPay, 61 | getTypedTransactions, 62 | getTypeValue, 63 | getCardsPerUserId, 64 | dropTransactions, 65 | dropCards 66 | }; 67 | -------------------------------------------------------------------------------- /src/sql/dump.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE 2 | users ( 3 | id SERIAL PRIMARY KEY, 4 | cpf VARCHAR(11) NOT NULL, 5 | name VARCHAR(75) NOT NULL, 6 | email VARCHAR(75) NOT NULL UNIQUE, 7 | phone VARCHAR(11) NOT NULL UNIQUE, 8 | password VARCHAR(50) NOT NULL, 9 | balance FLOAT DEFAULT 0 10 | ); 11 | 12 | CREATE TABLE 13 | transactions ( 14 | id SERIAL PRIMARY KEY, 15 | description VARCHAR(25) NOT NULL, 16 | value FLOAT NOT NULL, 17 | date TIMESTAMP DEFAULT current_timestamp, 18 | user_id INTEGER REFERENCES users (id) NOT NULL, 19 | type VARCHAR(6) NOT NULL 20 | ); 21 | 22 | CREATE TABLE 23 | credit_cards ( 24 | id SERIAL PRIMARY KEY, 25 | card_number VARCHAR(16) NOT NULL, 26 | cardholder_name VARCHAR(75) NOT NULL, 27 | expiration_date VARCHAR(5) NOT NULL, 28 | cvv VARCHAR(3) NOT NULL, 29 | user_id INT REFERENCES users (id) NOT NULL, 30 | created_at TIMESTAMP DEFAULT current_timestamp, 31 | balance REFERENCES users (balance) DEFAULT 0, 32 | password VARCHAR(6) NOT NULL 33 | ); 34 | 35 | CREATE TABLE 36 | debit_cards ( 37 | id SERIAL PRIMARY KEY, 38 | card_number VARCHAR(16) NOT NULL, 39 | cardholder_name VARCHAR(75) NOT NULL, 40 | expiration_date VARCHAR(5) NOT NULL, 41 | cvv VARCHAR(3) NOT NULL, 42 | user_id INT REFERENCES users (id) NOT NULL unique, 43 | created_at TIMESTAMP DEFAULT current_timestamp, 44 | password VARCHAR(6) NOT NULL 45 | ); 46 | -------------------------------------------------------------------------------- /src/models/user/index.ts: -------------------------------------------------------------------------------- 1 | import { UpdateUserParams } from "./UpdateUserParams"; 2 | import { LoginUserParams } from "./LoginUserParams"; 3 | import { DatabaseUserParams } from "./DatabaseUserParams"; 4 | import { ReturnedDatabaseUserParams } from "./ReturnedDatabaseUserParams"; 5 | import { UpdateUserEmailParams } from "./UpdateUserEmailParams"; 6 | import { UpdateUserPasswordParams } from "./UpdateUserPasswordParams"; 7 | import { UserParams } from "./UserParams"; 8 | import { InsertCardParams } from "./InsertCardParams"; 9 | import { CardParams } from "./CardParams"; 10 | import { ValidateCardParams } from "./ValidateCardParams"; 11 | import { DatabaseCardParams } from "./DatabaseCardParams"; 12 | import { UpdateCardPasswordParams } from "./UpdateCardPasswordParams"; 13 | import { RefreshCardParams } from "./RefreshCardParams"; 14 | import { UpdateUserPhoneParams } from "./UpdateUserPhoneParams"; 15 | import { DeleteUserParams } from "./DeleteUserParams"; 16 | import { RefreshUserParams } from "./RefreshUserParams"; 17 | 18 | export { 19 | UpdateUserParams, 20 | LoginUserParams, 21 | DatabaseUserParams, 22 | ReturnedDatabaseUserParams, 23 | UpdateUserEmailParams, 24 | UpdateUserPasswordParams, 25 | UserParams, 26 | InsertCardParams, 27 | CardParams, 28 | ValidateCardParams, 29 | DatabaseCardParams, 30 | UpdateCardPasswordParams, 31 | RefreshCardParams, 32 | UpdateUserPhoneParams, 33 | DeleteUserParams, 34 | RefreshUserParams 35 | }; 36 | -------------------------------------------------------------------------------- /src/services/transaction/insertPixAndReturn.ts: -------------------------------------------------------------------------------- 1 | import { Request } from "express"; 2 | import { PixParams } from "../../models"; 3 | import { getToken, validatePassword } from "../../utils"; 4 | import { 5 | undefinedUser, 6 | validateOutput, 7 | validatePix 8 | } from "../../providers"; 9 | import { 10 | createNewPix, 11 | createNewTransaction, 12 | getUserPerId, 13 | getUserPerCpf 14 | } from "../../repositories"; 15 | 16 | export default async function insertPixAndReturn(req: Request, params: PixParams) { 17 | const cpfUser = await getUserPerCpf(params.cpf); 18 | 19 | undefinedUser(cpfUser); 20 | 21 | const userId = getToken(req); 22 | 23 | const user = await getUserPerId(userId); 24 | 25 | undefinedUser(user); 26 | 27 | validatePix(user.cpf, params.cpf); 28 | 29 | validateOutput(user.balance, params.value); 30 | 31 | await validatePassword(params.password, user.password); 32 | 33 | const pixParams = { 34 | cpf: params.cpf, 35 | value: params.value, 36 | user_id: userId 37 | }; 38 | 39 | await createNewPix(pixParams); 40 | 41 | let transactionParams = { 42 | type: "output", 43 | description: "pix", 44 | value: params.value 45 | }; 46 | 47 | const responseTransaction = await createNewTransaction(transactionParams, userId); 48 | 49 | transactionParams = { 50 | type: "input", 51 | description: "pix", 52 | value: params.value 53 | }; 54 | 55 | await createNewTransaction(transactionParams, cpfUser.id); 56 | 57 | return responseTransaction; 58 | }; 59 | -------------------------------------------------------------------------------- /src/models/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | UpdateUserParams, 3 | LoginUserParams, 4 | DatabaseUserParams, 5 | ReturnedDatabaseUserParams, 6 | UpdateUserEmailParams, 7 | UpdateUserPasswordParams, 8 | UserParams, 9 | InsertCardParams, 10 | CardParams, 11 | ValidateCardParams, 12 | DatabaseCardParams, 13 | UpdateCardPasswordParams, 14 | RefreshCardParams, 15 | UpdateUserPhoneParams, 16 | DeleteUserParams, 17 | RefreshUserParams 18 | } from "./user"; 19 | 20 | import { 21 | TransactionParams, 22 | DatabaseTransactionParams, 23 | DeleteTransactionParams, 24 | OutputTransactionParams, 25 | CardTransactionParams, 26 | PixParams, 27 | DepositParams, 28 | CardPayParams, 29 | NewPixParams, 30 | GetCardPerUserIdParams, 31 | WithdrawParams, 32 | CardType 33 | } from "./transaction"; 34 | 35 | export { 36 | UpdateUserParams, 37 | LoginUserParams, 38 | DatabaseUserParams, 39 | ReturnedDatabaseUserParams, 40 | TransactionParams, 41 | DatabaseTransactionParams, 42 | UpdateUserEmailParams, 43 | UpdateUserPasswordParams, 44 | UserParams, 45 | DeleteTransactionParams, 46 | OutputTransactionParams, 47 | CardParams, 48 | ValidateCardParams, 49 | DatabaseCardParams, 50 | InsertCardParams, 51 | CardTransactionParams, 52 | UpdateCardPasswordParams, 53 | RefreshCardParams, 54 | UpdateUserPhoneParams, 55 | PixParams, 56 | DepositParams, 57 | DeleteUserParams, 58 | CardPayParams, 59 | NewPixParams, 60 | RefreshUserParams, 61 | GetCardPerUserIdParams, 62 | WithdrawParams, 63 | CardType 64 | }; 65 | -------------------------------------------------------------------------------- /src/routes/userRoutes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | 3 | import { 4 | insertUser, 5 | loginUser, 6 | detailUser, 7 | updateUser, 8 | updateUserEmail, 9 | updateUserPassword, 10 | deleteUser, 11 | insertCard, 12 | updateCardPassword, 13 | updateUserPhone, 14 | detailCards 15 | } from "../controllers"; 16 | 17 | import { 18 | verifyUserBody, 19 | verifyLoginUserBody, 20 | auth, 21 | verifyUpdateEmailUserBody, 22 | verifyUpdateUserBody, 23 | verifyUpdatePasswordUserBody, 24 | verifyPassword, 25 | verifyCardBody, 26 | verifyUpdateCardPassword, 27 | verifyUpdatePhoneUserBody 28 | } from "../middlewares"; 29 | 30 | const UserRoutes = express(); 31 | 32 | UserRoutes.post( 33 | "/user", 34 | verifyUserBody, 35 | insertUser 36 | ); 37 | 38 | UserRoutes.post( 39 | "/login", 40 | verifyLoginUserBody, 41 | loginUser 42 | ); 43 | 44 | UserRoutes.use(auth); 45 | 46 | UserRoutes.get( 47 | "/user", 48 | detailUser 49 | ); 50 | 51 | UserRoutes.put( 52 | "/user", 53 | verifyUpdateUserBody, 54 | updateUser 55 | ); 56 | 57 | UserRoutes.patch( 58 | "/email", 59 | verifyUpdateEmailUserBody, 60 | updateUserEmail 61 | ); 62 | 63 | UserRoutes.patch( 64 | "/password", 65 | verifyUpdatePasswordUserBody, 66 | updateUserPassword 67 | ); 68 | 69 | UserRoutes.patch( 70 | "/phone", 71 | verifyUpdatePhoneUserBody, 72 | updateUserPhone 73 | ); 74 | 75 | UserRoutes.delete( 76 | "/user", 77 | verifyPassword, 78 | deleteUser 79 | ); 80 | 81 | UserRoutes.post( 82 | "/card", 83 | verifyCardBody, 84 | insertCard 85 | ); 86 | 87 | UserRoutes.get( 88 | "/card", 89 | detailCards 90 | ); 91 | 92 | UserRoutes.patch( 93 | "/card", 94 | verifyUpdateCardPassword, 95 | updateCardPassword 96 | ); 97 | 98 | export default UserRoutes; 99 | -------------------------------------------------------------------------------- /src/routes/transactionRoutes.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | 3 | import { 4 | insertTransaction, 5 | summaryTransactions, 6 | detailTransaction, 7 | deleteTransaction, 8 | insertDeposit, 9 | makeWithdraw, 10 | insertCardTransaction, 11 | insertPix, 12 | makeCardPay, 13 | getHistory 14 | } from "../controllers"; 15 | 16 | import { 17 | verifyTransactionBody, 18 | verifyType, 19 | verifyTypeofParams, 20 | verifyPassword, 21 | verifyOutputTransaction, 22 | verifyDepositTransaction, 23 | verifyCardTransaction, 24 | verifyPixValue, 25 | verifyCardPay, 26 | } from "../middlewares"; 27 | 28 | const transactionRoutes = express(); 29 | 30 | transactionRoutes.post( 31 | "/transaction", 32 | verifyType, 33 | verifyTransactionBody, 34 | insertTransaction 35 | ); 36 | 37 | transactionRoutes.get( 38 | "/transaction", 39 | summaryTransactions 40 | ); 41 | 42 | transactionRoutes.get( 43 | "/transaction/:id", 44 | verifyTypeofParams, 45 | detailTransaction 46 | ); 47 | 48 | transactionRoutes.delete( 49 | "/transaction/:id", 50 | verifyPassword, 51 | verifyTypeofParams, 52 | deleteTransaction 53 | ); 54 | 55 | transactionRoutes.post( 56 | "/deposit", 57 | verifyDepositTransaction, 58 | insertDeposit 59 | ); 60 | 61 | transactionRoutes.post( 62 | "/withdraw", 63 | verifyOutputTransaction, 64 | makeWithdraw 65 | ); 66 | 67 | transactionRoutes.post( 68 | "/transaction/card", 69 | verifyCardTransaction, 70 | insertCardTransaction 71 | ); 72 | 73 | transactionRoutes.post( 74 | "/pix", 75 | verifyPixValue, 76 | insertPix 77 | ); 78 | 79 | transactionRoutes.post( 80 | "/card/pay", 81 | verifyCardPay, 82 | makeCardPay 83 | ); 84 | 85 | transactionRoutes.get( 86 | "/history", 87 | getHistory 88 | ); 89 | 90 | export default transactionRoutes; 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsbank-api", 3 | "version": "1.0.0", 4 | "description": "API RESTful de simulações bancárias.", 5 | "main": "server.ts", 6 | "scripts": { 7 | "dev": "nodemon", 8 | "jest": "npx jest --detectOpenHandles", 9 | "docker-build": "docker build -t tsbank_api .", 10 | "docker-start": "docker run --name tsbank_api -p 3001:3001 tsbank_api || docker start tsbank_api", 11 | "docker-stop": "docker stop tsbank_api", 12 | "docker-test": "docker run --rm --name tsbank_api_tests -it tsbank_api yarn jest" 13 | }, 14 | "keywords": [ 15 | "bun", 16 | "yarn", 17 | "jwt", 18 | "bcrypt", 19 | "express", 20 | "crud", 21 | "sql", 22 | "typescript", 23 | "nodejs", 24 | "solid", 25 | "restful", 26 | "nodemon", 27 | "pg", 28 | "postgresql", 29 | "knex", 30 | "yup", 31 | "api", 32 | "dotenv", 33 | "eslint", 34 | "ts-node", 35 | "dayjs", 36 | "docker", 37 | "swagger", 38 | "swagger-ui-express", 39 | "swagger-jsdoc" 40 | ], 41 | "author": "Victor José Lopes Navarro", 42 | "license": "MIT", 43 | "dependencies": { 44 | "bcrypt": "^5.1.1", 45 | "cors": "^2.8.5", 46 | "dayjs": "^1.11.10", 47 | "dotenv": "^16.3.2", 48 | "express": "^4.18.2", 49 | "jsonwebtoken": "^9.0.2", 50 | "knex": "^3.1.0", 51 | "pg": "^8.11.3", 52 | "swagger-jsdoc": "^6.2.8", 53 | "swagger-ui-express": "^5.0.0", 54 | "yup": "^1.3.3" 55 | }, 56 | "devDependencies": { 57 | "@types/bcrypt": "^5.0.2", 58 | "@types/cors": "^2.8.17", 59 | "@types/express": "^4.17.21", 60 | "@types/jest": "^29.5.11", 61 | "@types/jsonwebtoken": "^9.0.5", 62 | "@types/supertest": "^2.0.16", 63 | "@types/swagger-jsdoc": "^6.0.4", 64 | "@types/swagger-ui-express": "^4.1.6", 65 | "@typescript-eslint/eslint-plugin": "^6.19.1", 66 | "@typescript-eslint/parser": "^6.19.1", 67 | "eslint": "^8.56.0", 68 | "jest": "^29.7.0", 69 | "nodemon": "^3.0.3", 70 | "supertest": "^6.3.4", 71 | "ts-jest": "^29.1.2", 72 | "ts-node": "^10.9.2", 73 | "typescript": "^5.3.3" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /tests/user/detailUser.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | let bearerToken: string | undefined; 11 | let response: request.Response; 12 | 13 | const detailUser = async (token: string | undefined) => { 14 | response = await request(server) 15 | .get("/user") 16 | .set("Authorization", `Bearer ${token}`) 17 | .send(); 18 | 19 | return response; 20 | }; 21 | 22 | describe("Detail User Controller Tests", () => { 23 | beforeAll(async () => { 24 | bearerToken = await insertUserAndLogin(user, loginUser); 25 | }); 26 | 27 | it("Detail a user successfully", async () => { 28 | await detailUser(bearerToken); 29 | 30 | expect(response.status).toBe(200); 31 | expect(response.body).toHaveProperty("id"); 32 | expect(response.body).toHaveProperty("name", user.name); 33 | expect(response.body).toHaveProperty("email", user.email); 34 | expect(response.body).toHaveProperty("cpf", user.cpf); 35 | expect(response.body).toHaveProperty("phone", user.phone); 36 | expect(response.body).toHaveProperty("balance"); 37 | }); 38 | 39 | it("Jwt mal formed", async () => { 40 | let errorToken; 41 | 42 | await detailUser(errorToken); 43 | 44 | expect(response.status).toBe(401); 45 | expect(response.body).toHaveProperty("message", "jwt malformed"); 46 | }); 47 | 48 | it("Invalid signature", async () => { 49 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 50 | 51 | await detailUser(errorToken); 52 | 53 | expect(response.status).toBe(401); 54 | 55 | expect(response.body).toHaveProperty("message", "invalid signature"); 56 | }); 57 | 58 | it("Unauthorized", async () => { 59 | response = await unauthUser("get", server, "user"); 60 | 61 | expect(response.status).toBe(401); 62 | expect(response.body).toHaveProperty("message", "unauthorized"); 63 | }); 64 | 65 | it("User not found", async () => { 66 | await deleteUser(bearerToken, user.password); 67 | await detailUser(bearerToken); 68 | 69 | expect(response.status).toBe(404); 70 | expect(response.body).toHaveProperty("message", "user not found"); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /tests/user/loginUser.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { user } from "../models"; 4 | 5 | type LoginUserTestParams = { 6 | email: string | null; 7 | password: string | number | null; 8 | }; 9 | 10 | let logedUser: LoginUserTestParams; 11 | let response: request.Response; 12 | 13 | const loginUser = async (user: LoginUserTestParams) => { 14 | response = await request(server) 15 | .post("/login") 16 | .send(user); 17 | 18 | return response; 19 | }; 20 | 21 | describe("Login User Controller Tests", () => { 22 | beforeEach(async () => { 23 | logedUser = { 24 | email: "victorjln@gmail.com", 25 | password: "vtjln123" 26 | }; 27 | }); 28 | 29 | beforeAll(async () => { 30 | await request(server) 31 | .post("/user") 32 | .send(user); 33 | }); 34 | 35 | 36 | it("Login a user successfully", async () => { 37 | await loginUser(logedUser); 38 | 39 | expect(response.status).toBe(200); 40 | expect(response.body).toHaveProperty("user"); 41 | expect(response.body).toHaveProperty("token"); 42 | }); 43 | 44 | it("Data and hash must be strings", async () => { 45 | logedUser.password = 12345678; 46 | 47 | await loginUser(logedUser); 48 | 49 | expect(response.status).toBe(400); 50 | expect(response.body).toHaveProperty("message", "data and hash must be strings"); 51 | }); 52 | 53 | it("Password must be at least 8 characters", async () => { 54 | logedUser.password = "vtjln12"; 55 | 56 | await loginUser(logedUser); 57 | 58 | expect(response.status).toBe(400); 59 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 60 | }); 61 | 62 | it("Invalid email and/or password", async () => { 63 | logedUser.email = "victorjln2@gmail.com"; 64 | 65 | await loginUser(logedUser); 66 | 67 | expect(response.status).toBe(401); 68 | expect(response.body).toHaveProperty("message", "invalid email and/or password"); 69 | }); 70 | 71 | it("Email must be a valid email", async () => { 72 | logedUser.email = "victorjln@"; 73 | 74 | await loginUser(logedUser); 75 | 76 | expect(response.status).toBe(400); 77 | expect(response.body).toHaveProperty("message", "email must be a valid email"); 78 | }); 79 | 80 | it("Some request field missing", async () => { 81 | logedUser.password = null; 82 | 83 | await loginUser(logedUser); 84 | 85 | expect(response.status).toBe(400); 86 | expect(response.body).toHaveProperty("message", "password is a required field"); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /tests/transaction/getHistory.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, 6 | loginUser2, 7 | user, 8 | user2, 9 | withdraw 10 | } from "../models"; 11 | import { 12 | deleteUser, 13 | insertDeposit, 14 | insertUserAndLogin, 15 | makeWithdraw, 16 | unauthUser 17 | } from "../functions"; 18 | 19 | let bearerToken: string | undefined; 20 | let response: request.Response; 21 | 22 | const getHistory = async (token: string | undefined) => { 23 | response = await request(server) 24 | .get("/history") 25 | .set("Authorization", `Bearer ${token}`) 26 | .send(); 27 | 28 | return response; 29 | }; 30 | 31 | describe("Get a User Transaction History Controller Tests", () => { 32 | beforeEach(async () => { 33 | bearerToken = await insertUserAndLogin(user, loginUser); 34 | }); 35 | 36 | it("Get a user transaction history successfully", async () => { 37 | await insertDeposit(bearerToken, deposit); 38 | await makeWithdraw(bearerToken, withdraw); 39 | await getHistory(bearerToken); 40 | 41 | expect(response.status).toBe(200); 42 | }); 43 | 44 | it("Your account does not have any registered transaction", async () => { 45 | bearerToken = await insertUserAndLogin(user2, loginUser2); 46 | await getHistory(bearerToken); 47 | 48 | expect(response.status).toBe(404); 49 | expect(response.body).toHaveProperty("message", "your account does not have any registered transaction"); 50 | }); 51 | 52 | it("Jwt mal formed", async () => { 53 | let errorToken; 54 | 55 | await getHistory(errorToken); 56 | 57 | expect(response.status).toBe(401); 58 | expect(response.body).toHaveProperty("message", "jwt malformed"); 59 | }); 60 | 61 | it("Invalid signature", async () => { 62 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 63 | 64 | await getHistory(errorToken); 65 | 66 | expect(response.status).toBe(401); 67 | expect(response.body).toHaveProperty("message", "invalid signature"); 68 | }); 69 | 70 | it("Unauthorized", async () => { 71 | response = await unauthUser("get", server, "history"); 72 | 73 | expect(response.status).toBe(401); 74 | expect(response.body).toHaveProperty("message", "unauthorized"); 75 | }); 76 | 77 | it("User not found", async () => { 78 | await deleteUser(bearerToken, user.password); 79 | await getHistory(bearerToken); 80 | 81 | expect(response.status).toBe(404); 82 | expect(response.body).toHaveProperty("message", "user not found"); 83 | }); 84 | }); 85 | -------------------------------------------------------------------------------- /tests/transaction/summaryTransactions.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, 6 | loginUser2, 7 | user, 8 | user2 9 | } from "../models"; 10 | import { 11 | deleteUser, 12 | insertDeposit, 13 | insertUserAndLogin, 14 | unauthUser 15 | } from "../functions"; 16 | 17 | let bearerToken: string | undefined; 18 | let response: request.Response; 19 | 20 | const summaryTransactions = async (token: string | undefined) => { 21 | response = await request(server) 22 | .get("/transaction") 23 | .set("Authorization", `Bearer ${token}`) 24 | .send(); 25 | 26 | return response; 27 | }; 28 | 29 | describe("Summary Transactions Controller Tests", () => { 30 | beforeEach(async () => { 31 | bearerToken = await insertUserAndLogin(user, loginUser); 32 | }); 33 | 34 | it("Make a withdraw successfully", async () => { 35 | await insertDeposit(bearerToken, deposit); 36 | await summaryTransactions(bearerToken); 37 | 38 | expect(response.status).toBe(200); 39 | expect(response.body).toHaveProperty("input"); 40 | expect(response.body).toHaveProperty("output"); 41 | }); 42 | 43 | it("Your account does not have any registered transaction", async () => { 44 | bearerToken = await insertUserAndLogin(user2, loginUser2); 45 | await summaryTransactions(bearerToken); 46 | 47 | expect(response.status).toBe(404); 48 | expect(response.body).toHaveProperty("message", "your account does not have any registered transaction"); 49 | }); 50 | 51 | it("Jwt mal formed", async () => { 52 | let errorToken; 53 | 54 | await summaryTransactions(errorToken); 55 | 56 | expect(response.status).toBe(401); 57 | expect(response.body).toHaveProperty("message", "jwt malformed"); 58 | }); 59 | 60 | it("Invalid signature", async () => { 61 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 62 | 63 | await summaryTransactions(errorToken); 64 | 65 | expect(response.status).toBe(401); 66 | expect(response.body).toHaveProperty("message", "invalid signature"); 67 | }); 68 | 69 | it("Unauthorized", async () => { 70 | response = await unauthUser("get", server, "transaction"); 71 | 72 | expect(response.status).toBe(401); 73 | expect(response.body).toHaveProperty("message", "unauthorized"); 74 | }); 75 | 76 | it("User not found", async () => { 77 | await deleteUser(bearerToken, user.password); 78 | await summaryTransactions(bearerToken); 79 | 80 | expect(response.status).toBe(404); 81 | expect(response.body).toHaveProperty("message", "user not found"); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /tests/user/detailCards.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | insertUserAndLogin, 5 | unauthUser, 6 | deleteUser, 7 | insertCard, 8 | deleteCard 9 | } from "../functions"; 10 | import { 11 | user, 12 | credit, 13 | debit, 14 | loginUser, 15 | } from "../models"; 16 | 17 | let bearerToken: string | undefined; 18 | let response: request.Response; 19 | 20 | const detailCards = async (token: string | undefined) => { 21 | response = await request(server) 22 | .get("/card") 23 | .set("Authorization", `Bearer ${token}`) 24 | .send(); 25 | 26 | return response; 27 | }; 28 | 29 | describe("Detail a User Cards Controller Tests", () => { 30 | beforeAll(async () => { 31 | bearerToken = await insertUserAndLogin(user, loginUser); 32 | }); 33 | 34 | it("Detail a user cards successfully", async () => { 35 | await insertCard(bearerToken, credit); 36 | await insertCard(bearerToken, debit); 37 | await detailCards(bearerToken); 38 | 39 | expect(response.status).toBe(200); 40 | expect(response.body[ 0 ]).toHaveProperty("credit"); 41 | expect(response.body[ 1 ]).toHaveProperty("debit"); 42 | }); 43 | 44 | it("This user does not have a card", async () => { 45 | await deleteCard("credit"); 46 | await deleteCard("debit"); 47 | await detailCards(bearerToken); 48 | 49 | expect(response.status).toBe(404); 50 | 51 | expect(response.body).toHaveProperty("message", "this user does not have a card"); 52 | }); 53 | 54 | it("Jwt mal formed", async () => { 55 | let errorToken; 56 | 57 | await detailCards(errorToken); 58 | 59 | expect(response.status).toBe(401); 60 | expect(response.body).toHaveProperty("message", "jwt malformed"); 61 | }); 62 | 63 | it("Invalid signature", async () => { 64 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 65 | 66 | await detailCards(errorToken); 67 | 68 | expect(response.status).toBe(401); 69 | expect(response.body).toHaveProperty("message", "invalid signature"); 70 | }); 71 | 72 | it("Unauthorized", async () => { 73 | response = await unauthUser("get", server, "card"); 74 | 75 | expect(response.status).toBe(401); 76 | expect(response.body).toHaveProperty("message", "unauthorized"); 77 | }); 78 | 79 | it("User not found", async () => { 80 | await deleteUser(bearerToken, user.password); 81 | await detailCards(bearerToken); 82 | 83 | expect(response.status).toBe(404); 84 | expect(response.body).toHaveProperty("message", "user not found"); 85 | }); 86 | 87 | afterEach(async () => { 88 | await deleteCard("credit"); 89 | await deleteCard("debit"); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /tests/user/deleteUser.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { insertUserAndLogin, unauthUser } from "../functions"; 4 | import { loginUser, user } from "../models"; 5 | 6 | type DeleteUserTestParams = { 7 | password: string | null; 8 | }; 9 | 10 | const deleteUser = async (token: string | undefined, password: string | null) => { 11 | response = await request(server) 12 | .delete("/user") 13 | .set("Authorization", `Bearer ${token}`) 14 | .send({ password }); 15 | 16 | return response; 17 | }; 18 | 19 | let deletedUser: DeleteUserTestParams; 20 | let bearerToken: string | undefined; 21 | let response: request.Response; 22 | 23 | describe("Delete User Controller Tests", () => { 24 | beforeEach(async () => { 25 | deletedUser = { 26 | password: "vtjln123" 27 | }; 28 | 29 | bearerToken = await insertUserAndLogin(user, loginUser); 30 | }); 31 | 32 | it("Delete a user successfully", async () => { 33 | await deleteUser(bearerToken, deletedUser.password); 34 | 35 | expect(response.status).toBe(200); 36 | expect(response.body).toHaveProperty("message", "your account has been deleted"); 37 | }); 38 | 39 | it("Invalid password", async () => { 40 | deletedUser.password = "vtjln321"; 41 | 42 | await deleteUser(bearerToken, deletedUser.password); 43 | 44 | expect(response.status).toBe(401); 45 | expect(response.body).toHaveProperty("message", "invalid password"); 46 | }); 47 | 48 | it("Password must be at least 8 characters", async () => { 49 | deletedUser.password = "vtjln12"; 50 | 51 | await deleteUser(bearerToken, deletedUser.password); 52 | 53 | expect(response.status).toBe(400); 54 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 55 | }); 56 | 57 | it("Jwt mal formed", async () => { 58 | let errorToken; 59 | 60 | await deleteUser(errorToken, deletedUser.password); 61 | 62 | expect(response.status).toBe(401); 63 | expect(response.body).toHaveProperty("message", "jwt malformed"); 64 | }); 65 | 66 | it("Invalid signature", async () => { 67 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 68 | 69 | await deleteUser(errorToken, deletedUser.password); 70 | 71 | expect(response.status).toBe(401); 72 | expect(response.body).toHaveProperty("message", "invalid signature"); 73 | }); 74 | 75 | it("Unauthorized", async () => { 76 | response = await unauthUser("delete", server, "user"); 77 | 78 | expect(response.status).toBe(401); 79 | expect(response.body).toHaveProperty("message", "unauthorized"); 80 | }); 81 | 82 | it("User not found", async () => { 83 | await deleteUser(bearerToken, deletedUser.password); 84 | await deleteUser(bearerToken, deletedUser.password); 85 | 86 | expect(response.status).toBe(404); 87 | expect(response.body).toHaveProperty("message", "user not found"); 88 | }); 89 | 90 | it("Some request field missing", async () => { 91 | deletedUser.password = null; 92 | 93 | await deleteUser(bearerToken, deletedUser.password); 94 | 95 | expect(response.status).toBe(400); 96 | expect(response.body).toHaveProperty("message", "password is a required field"); 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /tests/transaction/detailTransaction.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, 6 | loginUser2, 7 | user, 8 | user2 9 | } from "../models"; 10 | import { 11 | deleteUser, 12 | insertDeposit, 13 | insertUserAndLogin, 14 | unauthUser 15 | } from "../functions"; 16 | 17 | let bearerToken: string | undefined; 18 | let response: request.Response; 19 | 20 | const detailTransaction = async (token: string | undefined, id: string) => { 21 | response = await request(server) 22 | .get(`/transaction/${id}`) 23 | .set("Authorization", `Bearer ${token}`) 24 | .send(); 25 | 26 | return response; 27 | }; 28 | 29 | describe("Detail Transaction Controller Tests", () => { 30 | beforeEach(async () => { 31 | bearerToken = await insertUserAndLogin(user, loginUser); 32 | }); 33 | 34 | it("Detail a transaction successfully", async () => { 35 | const identifier = await insertDeposit(bearerToken, deposit); 36 | 37 | await detailTransaction(bearerToken, identifier.body.id); 38 | 39 | expect(response.status).toBe(200); 40 | expect(response.body).toHaveProperty("id", identifier.body.id); 41 | expect(response.body).toHaveProperty("description", identifier.body.description); 42 | expect(response.body).toHaveProperty("value", identifier.body.value); 43 | expect(response.body).toHaveProperty("date", identifier.body.date); 44 | expect(response.body).toHaveProperty("user_id", identifier.body.user_id); 45 | expect(response.body).toHaveProperty("type", identifier.body.type); 46 | }); 47 | 48 | it("Invalid value of 'id' parameter", async () => { 49 | await detailTransaction(bearerToken, "a"); 50 | 51 | expect(response.status).toBe(400); 52 | expect(response.body).toHaveProperty("message", "invalid value of 'id' parameter"); 53 | }); 54 | 55 | it("Transaction not found", async () => { 56 | bearerToken = await insertUserAndLogin(user2, loginUser2); 57 | await detailTransaction(bearerToken, "0"); 58 | 59 | expect(response.status).toBe(404); 60 | expect(response.body).toHaveProperty("message", "transaction not found"); 61 | }); 62 | 63 | it("Jwt mal formed", async () => { 64 | let errorToken; 65 | 66 | await detailTransaction(errorToken, "0"); 67 | 68 | expect(response.status).toBe(401); 69 | expect(response.body).toHaveProperty("message", "jwt malformed"); 70 | }); 71 | 72 | it("Invalid signature", async () => { 73 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 74 | 75 | await detailTransaction(errorToken, "0"); 76 | 77 | expect(response.status).toBe(401); 78 | expect(response.body).toHaveProperty("message", "invalid signature"); 79 | }); 80 | 81 | it("Unauthorized", async () => { 82 | response = await unauthUser("get", server, "transaction/id"); 83 | 84 | expect(response.status).toBe(401); 85 | expect(response.body).toHaveProperty("message", "unauthorized"); 86 | }); 87 | 88 | it("User not found", async () => { 89 | await deleteUser(bearerToken, user.password); 90 | await detailTransaction(bearerToken, "0"); 91 | 92 | expect(response.status).toBe(404); 93 | expect(response.body).toHaveProperty("message", "user not found"); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /tests/transaction/deleteTransaction.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, 6 | loginUser2, 7 | user, 8 | user2 9 | } from "../models"; 10 | import { 11 | deleteUser, 12 | insertDeposit, 13 | insertUserAndLogin, 14 | unauthUser 15 | } from "../functions"; 16 | 17 | type DeleteTransactionTestParams = { 18 | password: string; 19 | }; 20 | 21 | let deletedTransaction: DeleteTransactionTestParams; 22 | let bearerToken: string | undefined; 23 | let response: request.Response; 24 | 25 | const deleteTransaction = async (token: string | undefined, id: string, password: DeleteTransactionTestParams) => { 26 | response = await request(server) 27 | .delete(`/transaction/${id}`) 28 | .set("Authorization", `Bearer ${token}`) 29 | .send(password); 30 | 31 | return response; 32 | }; 33 | 34 | describe("Delete Transaction Controller Tests", () => { 35 | beforeEach(async () => { 36 | deletedTransaction = { 37 | password: user.password 38 | }; 39 | 40 | bearerToken = await insertUserAndLogin(user, loginUser); 41 | }); 42 | 43 | it("Delete a transaction successfully", async () => { 44 | const identifier = await insertDeposit(bearerToken, deposit); 45 | 46 | await deleteTransaction(bearerToken, identifier.body.id, deletedTransaction); 47 | 48 | expect(response.status).toBe(200); 49 | expect(response.body).toHaveProperty("message", "your transaction has been deleted successfully"); 50 | }); 51 | 52 | it("Invalid value of 'id' parameter", async () => { 53 | await deleteTransaction(bearerToken, "a", deletedTransaction); 54 | 55 | expect(response.status).toBe(400); 56 | expect(response.body).toHaveProperty("message", "invalid value of 'id' parameter"); 57 | }); 58 | 59 | it("Transaction not found", async () => { 60 | bearerToken = await insertUserAndLogin(user2, loginUser2); 61 | await deleteTransaction(bearerToken, "0", deletedTransaction); 62 | 63 | expect(response.status).toBe(404); 64 | expect(response.body).toHaveProperty("message", "transaction not found"); 65 | }); 66 | 67 | it("Jwt mal formed", async () => { 68 | let errorToken; 69 | 70 | await deleteTransaction(errorToken, "0", deletedTransaction); 71 | 72 | expect(response.status).toBe(401); 73 | expect(response.body).toHaveProperty("message", "jwt malformed"); 74 | }); 75 | 76 | it("Invalid signature", async () => { 77 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 78 | 79 | await deleteTransaction(errorToken, "0", deletedTransaction); 80 | 81 | expect(response.status).toBe(401); 82 | expect(response.body).toHaveProperty("message", "invalid signature"); 83 | }); 84 | 85 | it("Unauthorized", async () => { 86 | response = await unauthUser("get", server, "transaction/id"); 87 | 88 | expect(response.status).toBe(401); 89 | expect(response.body).toHaveProperty("message", "unauthorized"); 90 | }); 91 | 92 | it("User not found", async () => { 93 | await deleteUser(bearerToken, user.password); 94 | await deleteTransaction(bearerToken, "0", deletedTransaction); 95 | 96 | expect(response.status).toBe(404); 97 | expect(response.body).toHaveProperty("message", "user not found"); 98 | }); 99 | }); 100 | -------------------------------------------------------------------------------- /tests/user/updateUserPassword.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | type UpdatePasswordUserTestParams = { 11 | password: string | null; 12 | new_password: string | null; 13 | }; 14 | 15 | let updatedPasswordUser: UpdatePasswordUserTestParams; 16 | let bearerToken: string | undefined; 17 | let response: request.Response; 18 | 19 | const updatePasswordUser = async (token: string | undefined, user: UpdatePasswordUserTestParams) => { 20 | response = await request(server) 21 | .patch("/password") 22 | .set("Authorization", `Bearer ${token}`) 23 | .send(user); 24 | 25 | return response; 26 | }; 27 | 28 | describe("Update User Password Controller Tests", () => { 29 | beforeEach(async () => { 30 | updatedPasswordUser = { 31 | "new_password": "vtjln321", 32 | "password": "vtjln123" 33 | }; 34 | 35 | bearerToken = await insertUserAndLogin(user, loginUser); 36 | }); 37 | 38 | it("Update a password successfully", async () => { 39 | await updatePasswordUser(bearerToken, updatedPasswordUser); 40 | 41 | expect(response.status).toBe(201); 42 | expect(response.body).toHaveProperty("message", "your password has been changed successfully"); 43 | }); 44 | 45 | it("Password must be at least 8 characters", async () => { 46 | updatedPasswordUser.password = "vtjln12"; 47 | 48 | await updatePasswordUser(bearerToken, updatedPasswordUser); 49 | 50 | expect(response.status).toBe(400); 51 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 52 | }); 53 | 54 | it("Invalid password", async () => { 55 | updatedPasswordUser.password = "vtjln312"; 56 | 57 | await updatePasswordUser(bearerToken, updatedPasswordUser); 58 | 59 | expect(response.status).toBe(401); 60 | expect(response.body).toHaveProperty("message", "invalid password"); 61 | }); 62 | 63 | it("Jwt mal formed", async () => { 64 | let errorToken; 65 | 66 | await updatePasswordUser(errorToken, updatedPasswordUser); 67 | 68 | expect(response.status).toBe(401); 69 | 70 | expect(response.body).toHaveProperty("message", "jwt malformed"); 71 | }); 72 | 73 | it("Invalid signature", async () => { 74 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 75 | 76 | await updatePasswordUser(errorToken, updatedPasswordUser); 77 | 78 | expect(response.status).toBe(401); 79 | expect(response.body).toHaveProperty("message", "invalid signature"); 80 | }); 81 | 82 | it("Unauthorized", async () => { 83 | response = await unauthUser("patch", server, "password"); 84 | 85 | expect(response.status).toBe(401); 86 | expect(response.body).toHaveProperty("message", "unauthorized"); 87 | }); 88 | 89 | it("User not found", async () => { 90 | await deleteUser(bearerToken, updatedPasswordUser.password); 91 | await updatePasswordUser(bearerToken, updatedPasswordUser); 92 | 93 | expect(response.status).toBe(404); 94 | expect(response.body).toHaveProperty("message", "user not found"); 95 | }); 96 | 97 | it("Some request field missing", async () => { 98 | updatedPasswordUser.password = null; 99 | 100 | await updatePasswordUser(bearerToken, updatedPasswordUser); 101 | 102 | expect(response.status).toBe(400); 103 | expect(response.body).toHaveProperty("message", "password is a required field"); 104 | }); 105 | 106 | afterEach(async () => { 107 | await deleteUser(bearerToken, updatedPasswordUser.new_password); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /tests/user/insertUser.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import db from "../../src/data/connection"; 4 | 5 | type InsertUserTestParams = { 6 | name: string | null; 7 | email: string | null; 8 | password: string | null; 9 | cpf: string | null; 10 | phone: string | null; 11 | }; 12 | 13 | let user: InsertUserTestParams; 14 | let response: request.Response; 15 | 16 | const createUser = async (user: InsertUserTestParams) => { 17 | response = await request(server) 18 | .post("/user") 19 | .send(user); 20 | 21 | return response; 22 | }; 23 | 24 | describe("Insert User Controller Tests", () => { 25 | beforeEach(async () => { 26 | await db("users").delete("*"); 27 | 28 | user = { 29 | name: "Victor Navarro", 30 | cpf: "12345678931", 31 | phone: "21123456789", 32 | email: "victorjln@gmail.com", 33 | password: "vtjln123" 34 | }; 35 | }); 36 | 37 | it("Create a new user successfully", async () => { 38 | await createUser(user); 39 | 40 | expect(response.status).toBe(201); 41 | expect(response.body).toHaveProperty("id"); 42 | expect(response.body).toHaveProperty("name", user.name); 43 | expect(response.body).toHaveProperty("email", user.email); 44 | }); 45 | 46 | it("Password must be at least 8 characters", async () => { 47 | user.password = "vtjln12"; 48 | 49 | await createUser(user); 50 | 51 | expect(response.status).toBe(400); 52 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 53 | }); 54 | 55 | it("Cpf must be at least 11 characters", async () => { 56 | user.cpf = "1234567891"; 57 | 58 | await createUser(user); 59 | 60 | expect(response.status).toBe(400); 61 | expect(response.body).toHaveProperty("message", "cpf must be at least 11 characters"); 62 | }); 63 | 64 | it("This cpf already used per other user", async () => { 65 | await createUser(user); 66 | 67 | user.phone = "21123456788"; 68 | user.email = "victorjln2@gmail.com"; 69 | 70 | await createUser(user); 71 | 72 | expect(response.status).toBe(409); 73 | expect(response.body).toHaveProperty("message", "this cpf already used per other user"); 74 | }); 75 | 76 | it("Phone must be at least 10 characters", async () => { 77 | user.phone = "123456789"; 78 | 79 | await createUser(user); 80 | 81 | expect(response.status).toBe(400); 82 | expect(response.body).toHaveProperty("message", "phone must be at least 10 characters"); 83 | }); 84 | 85 | it("This phone already used per other user", async () => { 86 | await createUser(user); 87 | 88 | user.email = "victorjln2@gmail.com"; 89 | user.cpf = "12345678930"; 90 | 91 | await createUser(user); 92 | 93 | expect(response.status).toBe(409); 94 | expect(response.body).toHaveProperty("message", "this phone already used per other user"); 95 | }); 96 | 97 | it("Email must be a valid email", async () => { 98 | user.email = "victorjln@"; 99 | 100 | await createUser(user); 101 | 102 | expect(response.status).toBe(400); 103 | expect(response.body).toHaveProperty("message", "email must be a valid email"); 104 | }); 105 | 106 | it("This email already used per other user", async () => { 107 | await createUser(user); 108 | 109 | user.phone = "21123456789"; 110 | user.cpf = "12345678932"; 111 | 112 | await createUser(user); 113 | 114 | expect(response.status).toBe(409); 115 | expect(response.body).toHaveProperty("message", "this email already used per other user"); 116 | }); 117 | 118 | it("Some request field missing", async () => { 119 | user.password = null; 120 | 121 | await createUser(user); 122 | 123 | expect(response.status).toBe(400); 124 | expect(response.body).toHaveProperty("message", "password is a required field"); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /tests/transaction/insertTransaction.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | type InsertTransaction = { 11 | type: string | null; 12 | description: string | null; 13 | value: number | null; 14 | }; 15 | 16 | let insertedTransaction: InsertTransaction; 17 | let bearerToken: string | undefined; 18 | let response: request.Response; 19 | 20 | const insertTransaction = async (token: string | undefined, transaction: InsertTransaction) => { 21 | response = await request(server) 22 | .post("/transaction") 23 | .set("Authorization", `Bearer ${token}`) 24 | .send(transaction); 25 | }; 26 | 27 | describe("Insert Transaction Controller Tests", () => { 28 | beforeEach(async () => { 29 | insertedTransaction = { 30 | "type": "input", 31 | "description": "credit", 32 | "value": 300000 33 | }; 34 | 35 | bearerToken = await insertUserAndLogin(user, loginUser); 36 | }); 37 | 38 | it("Insert a deposit successfully", async () => { 39 | await insertTransaction(bearerToken, insertedTransaction); 40 | 41 | expect(response.status).toBe(201); 42 | expect(response.body).toHaveProperty("id"); 43 | expect(response.body).toHaveProperty("description", insertedTransaction.description); 44 | expect(response.body).toHaveProperty("value", insertedTransaction.value); 45 | expect(response.body).toHaveProperty("date"); 46 | expect(response.body).toHaveProperty("user_id"); 47 | expect(response.body).toHaveProperty("type", insertedTransaction.type); 48 | }); 49 | 50 | it("Value must be greater than or equal to 0.01", async () => { 51 | insertedTransaction.value = 0; 52 | 53 | await insertTransaction(bearerToken, insertedTransaction); 54 | 55 | expect(response.status).toBe(400); 56 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 57 | }); 58 | 59 | it("Invalid value of type", async () => { 60 | insertedTransaction.type = ""; 61 | 62 | await insertTransaction(bearerToken, insertedTransaction); 63 | 64 | expect(response.status).toBe(400); 65 | expect(response.body).toHaveProperty("message", "invalid value of 'type'"); 66 | }); 67 | 68 | it("Jwt mal formed", async () => { 69 | let errorToken; 70 | 71 | await insertTransaction(errorToken, insertedTransaction); 72 | 73 | expect(response.status).toBe(401); 74 | expect(response.body).toHaveProperty("message", "jwt malformed"); 75 | }); 76 | 77 | it("Invalid signature", async () => { 78 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 79 | 80 | await insertTransaction(errorToken, insertedTransaction); 81 | 82 | expect(response.status).toBe(401); 83 | expect(response.body).toHaveProperty("message", "invalid signature"); 84 | }); 85 | 86 | it("Unauthorized", async () => { 87 | response = await unauthUser("post", server, "transaction"); 88 | 89 | expect(response.status).toBe(401); 90 | expect(response.body).toHaveProperty("message", "unauthorized"); 91 | }); 92 | 93 | it("User not found", async () => { 94 | await deleteUser(bearerToken, user.password); 95 | await insertTransaction(bearerToken, insertedTransaction); 96 | 97 | expect(response.status).toBe(404); 98 | expect(response.body).toHaveProperty("message", "user not found"); 99 | }); 100 | 101 | it("Some request field missing", async () => { 102 | insertedTransaction.description = null; 103 | 104 | await insertTransaction(bearerToken, insertedTransaction); 105 | 106 | expect(response.status).toBe(400); 107 | expect(response.body).toHaveProperty("message", "description is a required field"); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /tests/user/updateUserPhone.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { deleteUser, insertUserAndLogin, unauthUser } from "../functions"; 5 | 6 | type UpdatePhoneUserTestParams = { 7 | new_phone: string | null; 8 | password: string | null; 9 | }; 10 | 11 | let updatedPhoneUser: UpdatePhoneUserTestParams; 12 | let bearerToken: string | undefined; 13 | let response: request.Response; 14 | 15 | const updatePhoneUser = async (token: string | undefined, user: UpdatePhoneUserTestParams) => { 16 | response = await request(server) 17 | .patch("/phone") 18 | .set("Authorization", `Bearer ${token}`) 19 | .send(user); 20 | 21 | return response; 22 | }; 23 | 24 | describe("Update User Phone Controller Tests", () => { 25 | beforeEach(async () => { 26 | updatedPhoneUser = { 27 | "new_phone": "21987654321", 28 | "password": "vtjln123" 29 | }; 30 | 31 | bearerToken = await insertUserAndLogin(user, loginUser); 32 | }); 33 | 34 | it("Update a phone successfully", async () => { 35 | await updatePhoneUser(bearerToken, updatedPhoneUser); 36 | 37 | expect(response.status).toBe(201); 38 | expect(response.body).toHaveProperty("message", `your phone has been changed successfully, now is '${updatedPhoneUser.new_phone}'`); 39 | }); 40 | 41 | it("Phone must be a valid phone", async () => { 42 | updatedPhoneUser.new_phone = "211234567"; 43 | 44 | await updatePhoneUser(bearerToken, updatedPhoneUser); 45 | 46 | expect(response.status).toBe(400); 47 | expect(response.body).toHaveProperty("message", "new_phone must be at least 10 characters"); 48 | }); 49 | 50 | it("This phone already used per other user", async () => { 51 | await updatePhoneUser(bearerToken, updatedPhoneUser); 52 | 53 | await updatePhoneUser(bearerToken, updatedPhoneUser); 54 | 55 | expect(response.status).toBe(409); 56 | expect(response.body).toHaveProperty("message", "this phone already used per other user"); 57 | }); 58 | 59 | it("Password must be at least 8 characters", async () => { 60 | updatedPhoneUser.password = "vtjln12"; 61 | 62 | await updatePhoneUser(bearerToken, updatedPhoneUser); 63 | 64 | expect(response.status).toBe(400); 65 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 66 | }); 67 | 68 | it("Invalid password", async () => { 69 | updatedPhoneUser.password = "vtjln321"; 70 | 71 | await updatePhoneUser(bearerToken, updatedPhoneUser); 72 | 73 | expect(response.status).toBe(401); 74 | expect(response.body).toHaveProperty("message", "invalid password"); 75 | }); 76 | 77 | it("Jwt mal formed", async () => { 78 | let errorToken; 79 | 80 | await updatePhoneUser(errorToken, updatedPhoneUser); 81 | 82 | expect(response.status).toBe(401); 83 | 84 | expect(response.body).toHaveProperty("message", "jwt malformed"); 85 | }); 86 | 87 | it("Invalid signature", async () => { 88 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 89 | 90 | await updatePhoneUser(errorToken, updatedPhoneUser); 91 | 92 | expect(response.status).toBe(401); 93 | expect(response.body).toHaveProperty("message", "invalid signature"); 94 | }); 95 | 96 | it("Unauthorized", async () => { 97 | response = await unauthUser("patch", server, "phone"); 98 | 99 | expect(response.status).toBe(401); 100 | expect(response.body).toHaveProperty("message", "unauthorized"); 101 | }); 102 | 103 | it("User not found", async () => { 104 | await deleteUser(bearerToken, updatedPhoneUser.password); 105 | await updatePhoneUser(bearerToken, updatedPhoneUser); 106 | 107 | expect(response.status).toBe(404); 108 | expect(response.body).toHaveProperty("message", "user not found"); 109 | }); 110 | 111 | it("Some request field missing", async () => { 112 | updatedPhoneUser.password = null; 113 | 114 | await updatePhoneUser(bearerToken, updatedPhoneUser); 115 | 116 | expect(response.status).toBe(400); 117 | expect(response.body).toHaveProperty("message", "password is a required field"); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /tests/user/updateUserEmail.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | type UpdateEmailUserTestParams = { 11 | new_email: string | null; 12 | password: string | null; 13 | }; 14 | 15 | let updatedEmailUser: UpdateEmailUserTestParams; 16 | let bearerToken: string | undefined; 17 | let response: request.Response; 18 | 19 | const updateEmailUser = async (token: string | undefined, user: UpdateEmailUserTestParams) => { 20 | response = await request(server) 21 | .patch("/email") 22 | .set("Authorization", `Bearer ${token}`) 23 | .send(user); 24 | 25 | return response; 26 | }; 27 | 28 | describe("Update User Email Controller Tests", () => { 29 | beforeEach(async () => { 30 | updatedEmailUser = { 31 | "new_email": "victorjln2@gmail.com", 32 | "password": "vtjln123" 33 | }; 34 | 35 | bearerToken = await insertUserAndLogin(user, loginUser); 36 | }); 37 | 38 | it("Update a email successfully", async () => { 39 | await updateEmailUser(bearerToken, updatedEmailUser); 40 | 41 | expect(response.status).toBe(201); 42 | expect(response.body).toHaveProperty("message", `your email has been changed successfully, now is '${updatedEmailUser.new_email}'`); 43 | }); 44 | 45 | it("Email must be a valid email", async () => { 46 | updatedEmailUser.new_email = "victorjln@"; 47 | 48 | await updateEmailUser(bearerToken, updatedEmailUser); 49 | 50 | expect(response.status).toBe(400); 51 | expect(response.body).toHaveProperty("message", "new_email must be a valid email"); 52 | }); 53 | 54 | it("This email already used per other user", async () => { 55 | await updateEmailUser(bearerToken, updatedEmailUser); 56 | 57 | await updateEmailUser(bearerToken, updatedEmailUser); 58 | 59 | expect(response.status).toBe(409); 60 | expect(response.body).toHaveProperty("message", "this email already used per other user"); 61 | }); 62 | 63 | it("Password must be at least 8 characters", async () => { 64 | updatedEmailUser.password = "vtjln12"; 65 | 66 | await updateEmailUser(bearerToken, updatedEmailUser); 67 | 68 | expect(response.status).toBe(400); 69 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 70 | }); 71 | 72 | it("Invalid password", async () => { 73 | updatedEmailUser.password = "vtjln321"; 74 | 75 | await updateEmailUser(bearerToken, updatedEmailUser); 76 | 77 | expect(response.status).toBe(401); 78 | expect(response.body).toHaveProperty("message", "invalid password"); 79 | }); 80 | 81 | it("Jwt mal formed", async () => { 82 | let errorToken; 83 | 84 | await updateEmailUser(errorToken, updatedEmailUser); 85 | 86 | expect(response.status).toBe(401); 87 | expect(response.body).toHaveProperty("message", "jwt malformed"); 88 | }); 89 | 90 | it("Invalid signature", async () => { 91 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 92 | 93 | await updateEmailUser(errorToken, updatedEmailUser); 94 | 95 | expect(response.status).toBe(401); 96 | expect(response.body).toHaveProperty("message", "invalid signature"); 97 | }); 98 | 99 | it("Unauthorized", async () => { 100 | response = await unauthUser("patch", server, "email"); 101 | 102 | expect(response.status).toBe(401); 103 | expect(response.body).toHaveProperty("message", "unauthorized"); 104 | }); 105 | 106 | it("User not found", async () => { 107 | await deleteUser(bearerToken, updatedEmailUser.password); 108 | await updateEmailUser(bearerToken, updatedEmailUser); 109 | 110 | expect(response.status).toBe(404); 111 | expect(response.body).toHaveProperty("message", "user not found"); 112 | }); 113 | 114 | it("Some request field missing", async () => { 115 | updatedEmailUser.password = null; 116 | 117 | await updateEmailUser(bearerToken, updatedEmailUser); 118 | 119 | expect(response.status).toBe(400); 120 | expect(response.body).toHaveProperty("message", "password is a required field"); 121 | }); 122 | 123 | afterEach(async () => { 124 | await deleteUser(bearerToken, updatedEmailUser.password); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /tests/transaction/makeWithdraw.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, 6 | user 7 | } from "../models"; 8 | import { 9 | deleteUser, 10 | insertDeposit, 11 | insertUserAndLogin, 12 | unauthUser 13 | } from "../functions"; 14 | 15 | type MakeWithdrawTestParams = { 16 | value: number | null; 17 | password: string | null; 18 | }; 19 | 20 | let makedWithdraw: MakeWithdrawTestParams; 21 | let bearerToken: string | undefined; 22 | let response: request.Response; 23 | 24 | const makeWithdraw = async (token: string | undefined, withdraw: MakeWithdrawTestParams) => { 25 | response = await request(server) 26 | .post("/withdraw") 27 | .set("Authorization", `Bearer ${token}`) 28 | .send(withdraw); 29 | 30 | return response; 31 | }; 32 | 33 | describe("Make Withdraw Controller Tests", () => { 34 | beforeEach(async () => { 35 | makedWithdraw = { 36 | "value": 30000, 37 | "password": "vtjln123" 38 | }; 39 | 40 | bearerToken = await insertUserAndLogin(user, loginUser); 41 | }); 42 | 43 | it("Make a withdraw successfully", async () => { 44 | await insertDeposit(bearerToken, deposit); 45 | await makeWithdraw(bearerToken, makedWithdraw); 46 | 47 | expect(response.status).toBe(201); 48 | expect(response.body).toHaveProperty("id"); 49 | expect(response.body).toHaveProperty("description", "withdraw"); 50 | expect(response.body).toHaveProperty("value", makedWithdraw.value); 51 | expect(response.body).toHaveProperty("date"); 52 | expect(response.body).toHaveProperty("user_id"); 53 | expect(response.body).toHaveProperty("type", "output"); 54 | }); 55 | 56 | it("Insufficient balance to perform the transaction", async () => { 57 | await makeWithdraw(bearerToken, makedWithdraw); 58 | 59 | expect(response.status).toBe(400); 60 | expect(response.body).toHaveProperty("message", "insufficient balance to perform the transaction"); 61 | }); 62 | 63 | it("Value must be greater than or equal to 0.01", async () => { 64 | makedWithdraw.value = 0; 65 | 66 | await makeWithdraw(bearerToken, makedWithdraw); 67 | 68 | expect(response.status).toBe(400); 69 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 70 | }); 71 | 72 | it("Invalid password", async () => { 73 | makedWithdraw.password = "vtjln321"; 74 | 75 | await makeWithdraw(bearerToken, makedWithdraw); 76 | 77 | expect(response.status).toBe(401); 78 | expect(response.body).toHaveProperty("message", "invalid password"); 79 | }); 80 | 81 | it("Password must be at least 8 characters", async () => { 82 | makedWithdraw.password = "vtjln12"; 83 | 84 | await makeWithdraw(bearerToken, makedWithdraw); 85 | 86 | expect(response.status).toBe(400); 87 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 88 | }); 89 | 90 | it("Jwt mal formed", async () => { 91 | let errorToken; 92 | 93 | await makeWithdraw(errorToken, makedWithdraw); 94 | 95 | expect(response.status).toBe(401); 96 | expect(response.body).toHaveProperty("message", "jwt malformed"); 97 | }); 98 | 99 | it("Invalid signature", async () => { 100 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 101 | 102 | await makeWithdraw(errorToken, makedWithdraw); 103 | 104 | expect(response.status).toBe(401); 105 | expect(response.body).toHaveProperty("message", "invalid signature"); 106 | }); 107 | 108 | it("Unauthorized", async () => { 109 | response = await unauthUser("post", server, "withdraw"); 110 | 111 | expect(response.status).toBe(401); 112 | expect(response.body).toHaveProperty("message", "unauthorized"); 113 | }); 114 | 115 | it("User not found", async () => { 116 | await deleteUser(bearerToken, user.password); 117 | await makeWithdraw(bearerToken, makedWithdraw); 118 | 119 | expect(response.status).toBe(404); 120 | expect(response.body).toHaveProperty("message", "user not found"); 121 | }); 122 | 123 | it("Some request field missing", async () => { 124 | makedWithdraw.password = null; 125 | 126 | await makeWithdraw(bearerToken, makedWithdraw); 127 | 128 | expect(response.status).toBe(400); 129 | expect(response.body).toHaveProperty("message", "password is a required field"); 130 | }); 131 | }); 132 | -------------------------------------------------------------------------------- /tests/user/updateCardPassword.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | credit, 5 | loginUser, 6 | user 7 | } from "../models"; 8 | import { 9 | deleteCard, 10 | deleteUser, 11 | insertCard, 12 | insertUserAndLogin, 13 | unauthUser 14 | } from "../functions"; 15 | 16 | type UpdateCardPasswordTestParams = { 17 | "password": string | null; 18 | "new_password": string | null; 19 | "card_type": string | null; 20 | }; 21 | 22 | let updatedCardPassword: UpdateCardPasswordTestParams; 23 | let bearerToken: string | undefined; 24 | let response: request.Response; 25 | 26 | const updateCardPassword = async (token: string | undefined, card: UpdateCardPasswordTestParams) => { 27 | response = await request(server) 28 | .patch("/card") 29 | .set("Authorization", `Bearer ${token}`) 30 | .send(card); 31 | 32 | return response; 33 | }; 34 | 35 | describe("Update Card Password Controller Tests", () => { 36 | beforeEach(async () => { 37 | updatedCardPassword = { 38 | password: "123456", 39 | new_password: "654321", 40 | card_type: "credit" 41 | }; 42 | }); 43 | 44 | beforeAll(async () => { 45 | bearerToken = await insertUserAndLogin(user, loginUser); 46 | 47 | await insertCard(bearerToken, credit); 48 | }); 49 | 50 | it("Update a card password successfully", async () => { 51 | await updateCardPassword(bearerToken, updatedCardPassword); 52 | 53 | expect(response.status).toBe(201); 54 | expect(response.body).toHaveProperty("message", "password of your credit card has been updated successfully"); 55 | }); 56 | 57 | it("Invalid password", async () => { 58 | updatedCardPassword.password = "546783"; 59 | 60 | await updateCardPassword(bearerToken, updatedCardPassword); 61 | 62 | expect(response.status).toBe(401); 63 | expect(response.body).toHaveProperty("message", "invalid password"); 64 | }); 65 | 66 | it("Password must be at least 4 characters", async () => { 67 | updatedCardPassword.new_password = "vtj"; 68 | 69 | await updateCardPassword(bearerToken, updatedCardPassword); 70 | 71 | expect(response.status).toBe(400); 72 | expect(response.body).toHaveProperty("message", "new_password must be at least 4 characters"); 73 | }); 74 | 75 | it("Invalid value of 'Card Type'", async () => { 76 | updatedCardPassword.card_type = "bedit"; 77 | 78 | await updateCardPassword(bearerToken, updatedCardPassword); 79 | 80 | expect(response.status).toBe(400); 81 | expect(response.body).toHaveProperty("message", "invalid value of 'Card Type'"); 82 | }); 83 | 84 | it("Jwt mal formed", async () => { 85 | let errorToken; 86 | 87 | await updateCardPassword(errorToken, updatedCardPassword); 88 | 89 | expect(response.status).toBe(401); 90 | expect(response.body).toHaveProperty("message", "jwt malformed"); 91 | }); 92 | 93 | it("Invalid signature", async () => { 94 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 95 | 96 | await updateCardPassword(errorToken, updatedCardPassword); 97 | 98 | expect(response.status).toBe(401); 99 | expect(response.body).toHaveProperty("message", "invalid signature"); 100 | }); 101 | 102 | it("Unauthorized", async () => { 103 | response = await unauthUser("patch", server, "card"); 104 | 105 | expect(response.status).toBe(401); 106 | expect(response.body).toHaveProperty("message", "unauthorized"); 107 | }); 108 | 109 | it("Some request field missing", async () => { 110 | updatedCardPassword.password = null; 111 | 112 | await updateCardPassword(bearerToken, updatedCardPassword); 113 | 114 | expect(response.status).toBe(400); 115 | expect(response.body).toHaveProperty("message", "password is a required field"); 116 | }); 117 | 118 | it("This user not have a credit/debit card", async () => { 119 | await deleteCard(updatedCardPassword.card_type); 120 | 121 | await updateCardPassword(bearerToken, updatedCardPassword); 122 | 123 | expect(response.status).toBe(404); 124 | expect(response.body).toHaveProperty("message", `this user not have a ${updatedCardPassword.card_type?.toLowerCase()} card`); 125 | }); 126 | 127 | it("User not found", async () => { 128 | await deleteUser(bearerToken, user.password); 129 | await updateCardPassword(bearerToken, updatedCardPassword); 130 | 131 | expect(response.status).toBe(404); 132 | expect(response.body).toHaveProperty("message", "user not found"); 133 | }); 134 | }); 135 | -------------------------------------------------------------------------------- /tests/transaction/insertDeposit.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | type InsertDepositTestParams = { 11 | value: number | null; 12 | email: string | null; 13 | password: string | null; 14 | }; 15 | 16 | let insertedDeposit: InsertDepositTestParams; 17 | let bearerToken: string | undefined; 18 | let response: request.Response; 19 | 20 | const insertDeposit = async (token: string | undefined, deposit: InsertDepositTestParams) => { 21 | response = await request(server) 22 | .post("/deposit") 23 | .set("Authorization", `Bearer ${token}`) 24 | .send(deposit); 25 | }; 26 | 27 | describe("Insert Deposit Controller Tests", () => { 28 | beforeEach(async () => { 29 | insertedDeposit = { 30 | "value": 30000, 31 | "email": "victorjln@gmail.com", 32 | "password": "vtjln123" 33 | }; 34 | 35 | bearerToken = await insertUserAndLogin(user, loginUser); 36 | }); 37 | 38 | it("Insert a deposit successfully", async () => { 39 | await insertDeposit(bearerToken, insertedDeposit); 40 | 41 | expect(response.status).toBe(201); 42 | expect(response.body).toHaveProperty("id"); 43 | expect(response.body).toHaveProperty("description", "deposit"); 44 | expect(response.body).toHaveProperty("value", insertedDeposit.value); 45 | expect(response.body).toHaveProperty("date"); 46 | expect(response.body).toHaveProperty("user_id"); 47 | expect(response.body).toHaveProperty("type", "input"); 48 | }); 49 | 50 | it("Value must be greater than or equal to 0.01", async () => { 51 | insertedDeposit.value = 0; 52 | 53 | await insertDeposit(bearerToken, insertedDeposit); 54 | 55 | expect(response.status).toBe(400); 56 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 57 | }); 58 | 59 | it("Email must be a valid email", async () => { 60 | insertedDeposit.email = "victorjln@"; 61 | 62 | await insertDeposit(bearerToken, insertedDeposit); 63 | 64 | expect(response.status).toBe(400); 65 | expect(response.body).toHaveProperty("message", "email must be a valid email"); 66 | }); 67 | 68 | it("Email not found", async () => { 69 | insertedDeposit.email = "victorjln2@gmail.com"; 70 | 71 | await insertDeposit(bearerToken, insertedDeposit); 72 | 73 | expect(response.status).toBe(404); 74 | expect(response.body).toHaveProperty("message", "email not found"); 75 | }); 76 | 77 | it("Invalid password", async () => { 78 | insertedDeposit.password = "vtjln321"; 79 | 80 | await insertDeposit(bearerToken, insertedDeposit); 81 | 82 | expect(response.status).toBe(401); 83 | expect(response.body).toHaveProperty("message", "invalid password"); 84 | }); 85 | 86 | it("Password must be at least 8 characters", async () => { 87 | insertedDeposit.password = "vtjln12"; 88 | 89 | await insertDeposit(bearerToken, insertedDeposit); 90 | 91 | expect(response.status).toBe(400); 92 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 93 | }); 94 | 95 | it("Jwt mal formed", async () => { 96 | let errorToken; 97 | 98 | await insertDeposit(errorToken, insertedDeposit); 99 | 100 | expect(response.status).toBe(401); 101 | expect(response.body).toHaveProperty("message", "jwt malformed"); 102 | }); 103 | 104 | it("Invalid signature", async () => { 105 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 106 | 107 | await insertDeposit(errorToken, insertedDeposit); 108 | 109 | expect(response.status).toBe(401); 110 | expect(response.body).toHaveProperty("message", "invalid signature"); 111 | }); 112 | 113 | it("Unauthorized", async () => { 114 | response = await unauthUser("post", server, "deposit"); 115 | 116 | expect(response.status).toBe(401); 117 | expect(response.body).toHaveProperty("message", "unauthorized"); 118 | }); 119 | 120 | it("User not found", async () => { 121 | await deleteUser(bearerToken, user.password); 122 | await insertDeposit(bearerToken, insertedDeposit); 123 | 124 | expect(response.status).toBe(404); 125 | expect(response.body).toHaveProperty("message", "user not found"); 126 | }); 127 | 128 | it("Some request field missing", async () => { 129 | insertedDeposit.password = null; 130 | 131 | await insertDeposit(bearerToken, insertedDeposit); 132 | 133 | expect(response.status).toBe(400); 134 | expect(response.body).toHaveProperty("message", "password is a required field"); 135 | }); 136 | }); 137 | -------------------------------------------------------------------------------- /tests/transaction/makeCardPay.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | credit, 5 | deposit, 6 | loginUser, 7 | user 8 | } from "../models"; 9 | import { 10 | deleteCard, 11 | deleteUser, 12 | insertCard, 13 | insertDeposit, 14 | insertUserAndLogin, 15 | unauthUser 16 | } from "../functions"; 17 | 18 | type MakeCardPayTestParams = { 19 | password: string | null; 20 | value: number | null; 21 | }; 22 | 23 | let makedCardPay: MakeCardPayTestParams; 24 | let bearerToken: string | undefined; 25 | let response: request.Response; 26 | 27 | const makeCardPay = async (token: string | undefined, payment: MakeCardPayTestParams) => { 28 | response = await request(server) 29 | .post("/card/pay") 30 | .set("Authorization", `Bearer ${token}`) 31 | .send(payment); 32 | 33 | return response; 34 | }; 35 | 36 | describe("Make Card Payment Controller Tests", () => { 37 | beforeEach(async () => { 38 | makedCardPay = { 39 | "value": 30000, 40 | "password": "vtjln123" 41 | }; 42 | 43 | bearerToken = await insertUserAndLogin(user, loginUser); 44 | }); 45 | 46 | it("Make a card payment successfully", async () => { 47 | await insertCard(bearerToken, credit); 48 | await insertDeposit(bearerToken, deposit); 49 | await makeCardPay(bearerToken, makedCardPay); 50 | 51 | expect(response.status).toBe(201); 52 | expect(response.body).toHaveProperty("id"); 53 | expect(response.body).toHaveProperty("description", "card pay"); 54 | expect(response.body).toHaveProperty("value", makedCardPay.value); 55 | expect(response.body).toHaveProperty("date"); 56 | expect(response.body).toHaveProperty("user_id"); 57 | expect(response.body).toHaveProperty("type", "output"); 58 | }); 59 | 60 | it("Invalid password", async () => { 61 | makedCardPay.password = "vtjln321"; 62 | 63 | await makeCardPay(bearerToken, makedCardPay); 64 | 65 | expect(response.status).toBe(401); 66 | expect(response.body).toHaveProperty("message", "invalid password"); 67 | }); 68 | 69 | it("Password must be at least 8 characters", async () => { 70 | makedCardPay.password = "vtjln12"; 71 | 72 | await makeCardPay(bearerToken, makedCardPay); 73 | 74 | expect(response.status).toBe(400); 75 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 76 | }); 77 | 78 | it("Insufficient balance to perform the transaction", async () => { 79 | await makeCardPay(bearerToken, makedCardPay); 80 | 81 | expect(response.status).toBe(400); 82 | expect(response.body).toHaveProperty("message", "insufficient balance to perform the transaction"); 83 | }); 84 | 85 | it("Value must be greater than or equal to 0.01", async () => { 86 | makedCardPay.value = 0; 87 | 88 | await makeCardPay(bearerToken, makedCardPay); 89 | 90 | expect(response.status).toBe(400); 91 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 92 | }); 93 | 94 | it("Jwt mal formed", async () => { 95 | let errorToken; 96 | 97 | await makeCardPay(errorToken, makedCardPay); 98 | 99 | expect(response.status).toBe(401); 100 | expect(response.body).toHaveProperty("message", "jwt malformed"); 101 | }); 102 | 103 | it("Invalid signature", async () => { 104 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 105 | 106 | await makeCardPay(errorToken, makedCardPay); 107 | 108 | expect(response.status).toBe(401); 109 | expect(response.body).toHaveProperty("message", "invalid signature"); 110 | }); 111 | 112 | it("Unauthorized", async () => { 113 | response = await unauthUser("post", server, "card/pay"); 114 | 115 | expect(response.status).toBe(401); 116 | expect(response.body).toHaveProperty("message", "unauthorized"); 117 | }); 118 | 119 | it("Some request field missing", async () => { 120 | makedCardPay.password = null; 121 | 122 | await makeCardPay(bearerToken, makedCardPay); 123 | 124 | expect(response.status).toBe(400); 125 | expect(response.body).toHaveProperty("message", "password is a required field"); 126 | }); 127 | 128 | it("This user not have a credit/debit card", async () => { 129 | await deleteCard("credit"); 130 | 131 | await makeCardPay(bearerToken, makedCardPay); 132 | 133 | expect(response.status).toBe(404); 134 | expect(response.body).toHaveProperty("message", "this user not have a credit card"); 135 | }); 136 | 137 | it("User not found", async () => { 138 | await deleteUser(bearerToken, user.password); 139 | await makeCardPay(bearerToken, makedCardPay); 140 | 141 | expect(response.status).toBe(404); 142 | expect(response.body).toHaveProperty("message", "user not found"); 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /tests/transaction/insertPix.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | deposit, 5 | loginUser, loginUser2, 6 | user, 7 | user2 8 | } from "../models"; 9 | import { 10 | insertDeposit, 11 | insertUserAndLogin, 12 | unauthUser 13 | } from "../functions"; 14 | 15 | type InsertPixTestParams = { 16 | password: string | null; 17 | cpf: string | null; 18 | value: number | null; 19 | }; 20 | 21 | let insertedPix: InsertPixTestParams; 22 | let bearerToken: string | undefined; 23 | let response: request.Response; 24 | 25 | const insertPix = async (token: string | undefined, pix: InsertPixTestParams) => { 26 | response = await request(server) 27 | .post("/pix") 28 | .set("Authorization", `Bearer ${token}`) 29 | .send(pix); 30 | 31 | return response; 32 | }; 33 | 34 | describe("Insert Pix Controller Tests", () => { 35 | beforeEach(async () => { 36 | insertedPix = { 37 | "value": 30000, 38 | "cpf": "12345678921", 39 | "password": "vtjln123" 40 | }; 41 | 42 | bearerToken = await insertUserAndLogin(user, loginUser); 43 | }); 44 | 45 | beforeAll(async () => { 46 | await insertUserAndLogin(user2, loginUser2); 47 | }); 48 | 49 | it("Insert a pix successfully", async () => { 50 | await insertDeposit(bearerToken, deposit); 51 | await insertPix(bearerToken, insertedPix); 52 | 53 | expect(response.status).toBe(201); 54 | expect(response.body).toHaveProperty("id"); 55 | expect(response.body).toHaveProperty("description", "pix"); 56 | expect(response.body).toHaveProperty("value", insertedPix.value); 57 | expect(response.body).toHaveProperty("date"); 58 | expect(response.body).toHaveProperty("user_id"); 59 | expect(response.body).toHaveProperty("type", "output"); 60 | }); 61 | 62 | it("Insufficient balance to perform the transaction", async () => { 63 | await insertPix(bearerToken, insertedPix); 64 | 65 | expect(response.status).toBe(400); 66 | expect(response.body).toHaveProperty("message", "insufficient balance to perform the transaction"); 67 | }); 68 | 69 | it("Value must be greater than or equal to 0.01", async () => { 70 | insertedPix.value = 0; 71 | 72 | await insertPix(bearerToken, insertedPix); 73 | 74 | expect(response.status).toBe(400); 75 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 76 | }); 77 | 78 | it("Cpf must be at least 11 characters", async () => { 79 | insertedPix.cpf = "1234567891"; 80 | 81 | await insertPix(bearerToken, insertedPix); 82 | 83 | expect(response.status).toBe(400); 84 | expect(response.body).toHaveProperty("message", "cpf must be at least 11 characters"); 85 | }); 86 | 87 | it("User not found", async () => { 88 | insertedPix.cpf = "12121212121"; 89 | 90 | await insertPix(bearerToken, insertedPix); 91 | 92 | expect(response.status).toBe(404); 93 | expect(response.body).toHaveProperty("message", "user not found"); 94 | }); 95 | 96 | it("Invalid password", async () => { 97 | insertedPix.password = "vtjln321"; 98 | 99 | await insertDeposit(bearerToken, deposit); 100 | await insertPix(bearerToken, insertedPix); 101 | 102 | expect(response.status).toBe(401); 103 | expect(response.body).toHaveProperty("message", "invalid password"); 104 | }); 105 | 106 | it("Password must be at least 8 characters", async () => { 107 | insertedPix.password = "vtjln12"; 108 | 109 | await insertPix(bearerToken, insertedPix); 110 | 111 | expect(response.status).toBe(400); 112 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 113 | }); 114 | 115 | it("Jwt mal formed", async () => { 116 | let errorToken; 117 | 118 | await insertPix(errorToken, insertedPix); 119 | 120 | expect(response.status).toBe(401); 121 | expect(response.body).toHaveProperty("message", "jwt malformed"); 122 | }); 123 | 124 | it("Invalid signature", async () => { 125 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 126 | 127 | await insertPix(errorToken, insertedPix); 128 | 129 | expect(response.status).toBe(401); 130 | expect(response.body).toHaveProperty("message", "invalid signature"); 131 | }); 132 | 133 | it("Unauthorized", async () => { 134 | response = await unauthUser("post", server, "pix"); 135 | 136 | expect(response.status).toBe(401); 137 | expect(response.body).toHaveProperty("message", "unauthorized"); 138 | }); 139 | 140 | it("Some request field missing", async () => { 141 | insertedPix.password = null; 142 | 143 | await insertPix(bearerToken, insertedPix); 144 | 145 | expect(response.status).toBe(400); 146 | expect(response.body).toHaveProperty("message", "password is a required field"); 147 | }); 148 | }); 149 | -------------------------------------------------------------------------------- /tests/user/updateUser.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { loginUser, user } from "../models"; 4 | import { 5 | deleteUser, 6 | insertUserAndLogin, 7 | unauthUser 8 | } from "../functions"; 9 | 10 | type UpdateUserTestParams = { 11 | new_phone: string | null; 12 | new_email: string | null; 13 | new_password: string | null; 14 | password: string | null; 15 | }; 16 | 17 | const updateUser = async (token: string | undefined, user: UpdateUserTestParams) => { 18 | response = await request(server) 19 | .put("/user") 20 | .set("Authorization", `Bearer ${token}`) 21 | .send(user); 22 | 23 | return response; 24 | }; 25 | 26 | let updatedUser: UpdateUserTestParams; 27 | let bearerToken: string | undefined; 28 | let response: request.Response; 29 | 30 | describe("Update User Controller Tests", () => { 31 | beforeEach(async () => { 32 | updatedUser = { 33 | new_phone: "22123456789", 34 | new_email: "victorjln2@gmail.com", 35 | new_password: "vtjln321", 36 | password: "vtjln123" 37 | }; 38 | 39 | await deleteUser(bearerToken, updatedUser.new_password); 40 | 41 | bearerToken = await insertUserAndLogin(user, loginUser); 42 | }); 43 | 44 | it("Update a user successfully", async () => { 45 | await updateUser(bearerToken, updatedUser); 46 | 47 | expect(response.status).toBe(201); 48 | expect(response.body).toHaveProperty("id"); 49 | expect(response.body).toHaveProperty("name"); 50 | expect(response.body).toHaveProperty("email", updatedUser.new_email); 51 | }); 52 | 53 | it("Password must be at least 8 characters", async () => { 54 | updatedUser.password = "vtjln12"; 55 | 56 | await updateUser(bearerToken, updatedUser); 57 | 58 | expect(response.status).toBe(400); 59 | expect(response.body).toHaveProperty("message", "password must be at least 8 characters"); 60 | }); 61 | 62 | it("Invalid password", async () => { 63 | updatedUser.password = "vtjln321"; 64 | 65 | await updateUser(bearerToken, updatedUser); 66 | 67 | expect(response.status).toBe(401); 68 | expect(response.body).toHaveProperty("message", "invalid password"); 69 | }); 70 | 71 | it("Phone must be at least 10 characters", async () => { 72 | updatedUser.new_phone = "123456789"; 73 | 74 | await updateUser(bearerToken, updatedUser); 75 | 76 | expect(response.status).toBe(400); 77 | expect(response.body).toHaveProperty("message", "new_phone must be at least 10 characters"); 78 | }); 79 | 80 | it("This phone already used per other user", async () => { 81 | await updateUser(bearerToken, updatedUser); 82 | 83 | updatedUser.new_email = "victorjln3@gmail.com"; 84 | 85 | await updateUser(bearerToken, updatedUser); 86 | 87 | expect(response.status).toBe(409); 88 | expect(response.body).toHaveProperty("message", "this phone already used per other user"); 89 | }); 90 | 91 | it("Email must be a valid email", async () => { 92 | updatedUser.new_email = "victorjln@"; 93 | 94 | await updateUser(bearerToken, updatedUser); 95 | 96 | expect(response.status).toBe(400); 97 | expect(response.body).toHaveProperty("message", "new_email must be a valid email"); 98 | }); 99 | 100 | it("This email already used per other user", async () => { 101 | await updateUser(bearerToken, updatedUser); 102 | 103 | updatedUser.new_phone = "21123456789"; 104 | 105 | await updateUser(bearerToken, updatedUser); 106 | 107 | expect(response.status).toBe(409); 108 | expect(response.body).toHaveProperty("message", "this email already used per other user"); 109 | }); 110 | 111 | it("Jwt mal formed", async () => { 112 | let errorToken; 113 | 114 | await updateUser(errorToken, updatedUser); 115 | 116 | expect(response.status).toBe(401); 117 | expect(response.body).toHaveProperty("message", "jwt malformed"); 118 | }); 119 | 120 | it("Invalid signature", async () => { 121 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 122 | 123 | await updateUser(errorToken, updatedUser); 124 | 125 | expect(response.status).toBe(401); 126 | expect(response.body).toHaveProperty("message", "invalid signature"); 127 | }); 128 | 129 | it("Unauthorized", async () => { 130 | response = await unauthUser("put", server, "user"); 131 | 132 | expect(response.status).toBe(401); 133 | expect(response.body).toHaveProperty("message", "unauthorized"); 134 | }); 135 | 136 | it("User not found", async () => { 137 | await deleteUser(bearerToken, updatedUser.password); 138 | await updateUser(bearerToken, updatedUser); 139 | 140 | expect(response.status).toBe(404); 141 | expect(response.body).toHaveProperty("message", "user not found"); 142 | }); 143 | 144 | it("Some request field missing", async () => { 145 | updatedUser.password = null; 146 | 147 | await updateUser(bearerToken, updatedUser); 148 | 149 | expect(response.status).toBe(400); 150 | expect(response.body).toHaveProperty("message", "password is a required field"); 151 | }); 152 | }); 153 | -------------------------------------------------------------------------------- /tests/transaction/insertCardTransaction.test.ts: -------------------------------------------------------------------------------- 1 | import request from "supertest"; 2 | import server from "../../src/server"; 3 | import { 4 | debit, 5 | deposit, 6 | loginUser, 7 | user 8 | } from "../models"; 9 | import { 10 | deleteCard, 11 | deleteUser, 12 | insertCard, 13 | insertDeposit, 14 | insertUserAndLogin, 15 | unauthUser 16 | } from "../functions"; 17 | 18 | type InsertCardTransactionTestParams = { 19 | password: string | null; 20 | card_type: string | null; 21 | value: number | null; 22 | }; 23 | 24 | let insertedCardTransaction: InsertCardTransactionTestParams; 25 | let bearerToken: string | undefined; 26 | let response: request.Response; 27 | 28 | const insertCardTransaction = async (token: string | undefined, transaction: InsertCardTransactionTestParams) => { 29 | response = await request(server) 30 | .post("/transaction/card") 31 | .set("Authorization", `Bearer ${token}`) 32 | .send(transaction); 33 | 34 | return response; 35 | }; 36 | 37 | describe("Insert Card Transaction Controller Tests", () => { 38 | beforeEach(async () => { 39 | insertedCardTransaction = { 40 | "value": 30000, 41 | "card_type": "debit", 42 | "password": "123456" 43 | }; 44 | 45 | bearerToken = await insertUserAndLogin(user, loginUser); 46 | }); 47 | 48 | it("Insert a card transaction successfully", async () => { 49 | await insertCard(bearerToken, debit); 50 | await insertDeposit(bearerToken, deposit); 51 | await insertCardTransaction(bearerToken, insertedCardTransaction); 52 | 53 | expect(response.status).toBe(201); 54 | expect(response.body).toHaveProperty("id"); 55 | expect(response.body).toHaveProperty("description", insertedCardTransaction.card_type); 56 | expect(response.body).toHaveProperty("value", insertedCardTransaction.value); 57 | expect(response.body).toHaveProperty("date"); 58 | expect(response.body).toHaveProperty("user_id"); 59 | expect(response.body).toHaveProperty("type", "output"); 60 | }); 61 | 62 | it("Insufficient balance to perform the transaction", async () => { 63 | await insertCardTransaction(bearerToken, insertedCardTransaction); 64 | 65 | expect(response.status).toBe(400); 66 | expect(response.body).toHaveProperty("message", "insufficient balance to perform the transaction"); 67 | }); 68 | 69 | it("Value must be greater than or equal to 0.01", async () => { 70 | insertedCardTransaction.value = 0; 71 | 72 | await insertCardTransaction(bearerToken, insertedCardTransaction); 73 | 74 | expect(response.status).toBe(400); 75 | expect(response.body).toHaveProperty("message", "value must be greater than or equal to 0.01"); 76 | }); 77 | 78 | it("Invalid password", async () => { 79 | insertedCardTransaction.password = "1234"; 80 | 81 | await insertCardTransaction(bearerToken, insertedCardTransaction); 82 | 83 | expect(response.status).toBe(401); 84 | expect(response.body).toHaveProperty("message", "invalid password"); 85 | }); 86 | 87 | it("Password must be at least 4 characters", async () => { 88 | insertedCardTransaction.password = "vtj"; 89 | 90 | await insertCardTransaction(bearerToken, insertedCardTransaction); 91 | 92 | expect(response.status).toBe(400); 93 | expect(response.body).toHaveProperty("message", "password must be at least 4 characters"); 94 | }); 95 | 96 | it("Invalid value of 'Card Type'", async () => { 97 | insertedCardTransaction.card_type = "bedit"; 98 | 99 | await insertCardTransaction(bearerToken, insertedCardTransaction); 100 | 101 | expect(response.status).toBe(400); 102 | expect(response.body).toHaveProperty("message", "invalid value of 'Card Type'"); 103 | }); 104 | 105 | it("Jwt mal formed", async () => { 106 | let errorToken; 107 | 108 | await insertCardTransaction(errorToken, insertedCardTransaction); 109 | 110 | expect(response.status).toBe(401); 111 | expect(response.body).toHaveProperty("message", "jwt malformed"); 112 | }); 113 | 114 | it("Invalid signature", async () => { 115 | const errorToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; 116 | 117 | await insertCardTransaction(errorToken, insertedCardTransaction); 118 | 119 | expect(response.status).toBe(401); 120 | expect(response.body).toHaveProperty("message", "invalid signature"); 121 | }); 122 | 123 | it("Unauthorized", async () => { 124 | response = await unauthUser("post", server, "transaction/card"); 125 | 126 | expect(response.status).toBe(401); 127 | expect(response.body).toHaveProperty("message", "unauthorized"); 128 | }); 129 | 130 | it("Some request field missing", async () => { 131 | insertedCardTransaction.password = null; 132 | 133 | await insertCardTransaction(bearerToken, insertedCardTransaction); 134 | 135 | expect(response.status).toBe(400); 136 | expect(response.body).toHaveProperty("message", "password is a required field"); 137 | }); 138 | 139 | it("This user not have a credit/debit card", async () => { 140 | await deleteCard(insertedCardTransaction.card_type); 141 | 142 | await insertCardTransaction(bearerToken, insertedCardTransaction); 143 | 144 | expect(response.status).toBe(404); 145 | expect(response.body).toHaveProperty("message", `this user not have a ${insertedCardTransaction.card_type?.toLowerCase()} card`); 146 | }); 147 | 148 | it("User not found", async () => { 149 | await deleteUser(bearerToken, user.password); 150 | await insertCardTransaction(bearerToken, insertedCardTransaction); 151 | 152 | expect(response.status).toBe(404); 153 | expect(response.body).toHaveProperty("message", "user not found"); 154 | }); 155 | }); 156 | --------------------------------------------------------------------------------