Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lor 214 list user #46

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e11008a
fix: adjust Credential Id to String -uuid
Daaaiii Jan 30, 2024
85b9ba6
LOR-214 update getCredentialByEmail to also receive an ID
Daaaiii Jan 30, 2024
8ba2c20
LOR-214 - add endpoint to get users
Daaaiii Jan 30, 2024
f5747d5
LOR-214 - fix: update function name getCredentialIdByEmailOrId
Daaaiii Jan 30, 2024
680a470
LOR-214 adjust test to use id as string
Daaaiii Jan 30, 2024
d622fbc
LOR-124: fix: remove console.log
Daaaiii Jan 30, 2024
3122b77
LOR-124: fix: update name of function to getCredentialIdByEmailOrId
Daaaiii Jan 30, 2024
c530e94
LOR-214: feat: add guard and swagger tags
Daaaiii Jan 30, 2024
1309b88
LOR-214 feat User decorator
Daaaiii Feb 6, 2024
4c93f0b
LOR-214 feat: add validation to check if logged user is the same as u…
Daaaiii Feb 6, 2024
f63d328
LOR-214 feat: add User decorator to check user logged
Daaaiii Feb 6, 2024
02baf6e
LOR-214 feat: update getCredentialIdByEmailOrId
Daaaiii Feb 6, 2024
5e51479
LOR-214 feat: add cid to login response
Daaaiii Feb 6, 2024
14e332c
LOR-214 fix: update id
Daaaiii Feb 7, 2024
1333fb5
LOR-214 fix: separa functions to get id by mail and by token
Daaaiii Feb 7, 2024
aa2b333
LOR-214: remove pid and cid from login response
Daaaiii Feb 7, 2024
2ab71e0
LOR-214: feat: add message to get account response
Daaaiii Feb 7, 2024
2cea824
LOR-214 - feat: add email to GetCredential type
Daaaiii Feb 7, 2024
a9bb6f0
LOR-214 - feat: add test to Account
Daaaiii Feb 7, 2024
25708db
fix identation
Daaaiii Feb 20, 2024
0e4b97f
Update prisma/schema.prisma
Daaaiii Feb 20, 2024
dc16903
Update src/decorators/account.decorator.ts
Daaaiii Feb 20, 2024
48e3c13
Update src/modules/account/account.repository.ts
Daaaiii Feb 20, 2024
5161607
Update src/modules/account/account.repository.ts
Daaaiii Feb 20, 2024
3c4b205
fix: remove email from getCredentialIdByEmail return
Daaaiii Feb 20, 2024
99fb626
fix: remove wrong object
Daaaiii Feb 20, 2024
742e7ce
refactor: use findunique at getCredentialId
Kauanedev Apr 16, 2024
daa1484
fix: remove id from getCredentialId response
Kauanedev Apr 16, 2024
070f1d6
fix: remove id field from account entity
Kauanedev Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Warnings:

- The primary key for the `credentials` table will be changed. If it partially fails, the table could be left without primary key constraint.

*/
-- DropForeignKey
ALTER TABLE "parent_profiles" DROP CONSTRAINT "parent_profiles_credential_id_fkey";

-- DropForeignKey
ALTER TABLE "reset_password_info" DROP CONSTRAINT "reset_password_info_credential_id_fkey";

-- AlterTable
ALTER TABLE "credentials" DROP CONSTRAINT "credentials_pkey",
ALTER COLUMN "id" DROP DEFAULT,
ALTER COLUMN "id" SET DATA TYPE TEXT,
ADD CONSTRAINT "credentials_pkey" PRIMARY KEY ("id");
DROP SEQUENCE "credentials_id_seq";

-- AlterTable
ALTER TABLE "parent_profiles" ALTER COLUMN "credential_id" SET DATA TYPE TEXT;

-- AlterTable
ALTER TABLE "reset_password_info" ALTER COLUMN "credential_id" SET DATA TYPE TEXT;

-- AddForeignKey
ALTER TABLE "reset_password_info" ADD CONSTRAINT "reset_password_info_credential_id_fkey" FOREIGN KEY ("credential_id") REFERENCES "credentials"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "parent_profiles" ADD CONSTRAINT "parent_profiles_credential_id_fkey" FOREIGN KEY ("credential_id") REFERENCES "credentials"("id") ON DELETE CASCADE ON UPDATE CASCADE;
6 changes: 3 additions & 3 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ datasource db {
}

model Credential {
id Int @id @default(autoincrement())
id String @id @default(uuid())
email String @unique
password String
policiesAcceptedAt DateTime @map("policies_accepted_at")
Expand All @@ -29,7 +29,7 @@ model ResetPasswordInfo {
id Int @id @default(autoincrement())
recoveryToken String @unique @map("recovery_token")
expiresIn DateTime @updatedAt @map("expires_in")
credentialId Int @unique @map("credential_id")
credentialId String @unique @map("credential_id")
credential Credential @relation(fields: [credentialId], references: [id], onDelete: Cascade)

@@map("reset_password_info")
Expand All @@ -39,7 +39,7 @@ model ParentProfile {
id String @id @default(uuid())
fullname String
childrens ChildrenProfile[]
credentialId Int @unique @map("credential_id")
credentialId String @unique @map("credential_id")
credential Credential @relation(fields: [credentialId], references: [id], onDelete: Cascade)
updatedAt DateTime @updatedAt @map("updated_at")
createdAt DateTime @default(now()) @map("created_at")
Expand Down
8 changes: 8 additions & 0 deletions src/decorators/account.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createParamDecorator, type ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request['session.payload'].cid;
},
);
28 changes: 26 additions & 2 deletions src/modules/account/account.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { Controller, Post, Body, HttpCode, Put } from '@nestjs/common';
import {
Controller,
Post,
Body,
HttpCode,
Put,
Get,
UseGuards,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { ApiResponse, ApiTags } from '@nestjs/swagger';
import { ApiBearerAuth, ApiResponse, ApiTags } from '@nestjs/swagger';
import { MailService } from '../mail/mail.service';
import { AccountService } from './account.service';
import { responses } from 'src/globals/responses/docs';
Expand All @@ -11,6 +19,8 @@ import {
ResetPasswordDto,
SetPasswordDto,
} from './account.dto';
import { AuthorizationGuard, RequestToken } from '../../guard';
import { User } from '../../decorators/account.decorator';

@Controller('/auth')
export class AccountController {
Expand Down Expand Up @@ -105,4 +115,18 @@ export class AccountController {
message: 'Senha redefinida com sucesso',
};
}
@UseGuards(AuthorizationGuard)
@RequestToken({ type: 'access', role: 'user' })
@ApiBearerAuth('access')
@Get('/account')
@ApiTags('Account')
@HttpCode(200)
@ApiResponse(responses.ok)
@ApiResponse(responses.badRequest)
@ApiResponse(responses.unauthorized)
@ApiResponse(responses.internalError)
async getCredential(@User() id: string) {
const data = await this.accountService.getCredential(id);
return { message: 'Dados recebidos com sucesso', data };
}
}
7 changes: 7 additions & 0 deletions src/modules/account/account.entity.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ export type GetCredentialIdByEmailOutput = Pick<
>;
};
};
export type GetCredential = Pick<Credential, 'email'> & {
parentProfile: Pick<ParentProfile, 'fullname'> & {
childrens: Array<
Pick<ChildrenProfile, 'fullname' | 'birthdate' | 'gender'>
>;
};
};

export type getCredentialIdByRecoveryTokenInput = {
hashedToken: string;
Expand Down
36 changes: 32 additions & 4 deletions src/modules/account/account.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getCredentialIdByRecoveryTokenInput,
getCredentialIdByRecoveryTokenOutout,
SavePasswordInput,
GetCredential,
} from './account.entity';
import { handleErrors } from 'src/globals/errors';

Expand Down Expand Up @@ -47,13 +48,11 @@ export class AccountRepository {
}

async getCredentialIdByEmail(
hashedEmail: string,
hashedemail: string,
): Promise<GetCredentialIdByEmailOutput | void> {
const response = await this.prisma.credential
.findUnique({
where: {
email: hashedEmail,
},
where: { email: hashedemail },
select: {
id: true,
password: true,
Expand Down Expand Up @@ -81,6 +80,35 @@ export class AccountRepository {
return response;
}

async getCredentialId(id: string): Promise<GetCredential | void> {
const response = await this.prisma.credential
.findUnique({
where: { id },
select: {
email: true,
parentProfile: {
select: {
fullname: true,
childrens: {
select: {
id: true,
fullname: true,
gender: true,
birthdate: true,
},
},
},
},
},
})
.then((response) => {
return response;
})
.catch((error) => handleErrors(error));

return response;
}

async getCredentialIdByRecoveryToken(
input: getCredentialIdByRecoveryTokenInput,
): Promise<getCredentialIdByRecoveryTokenOutout> {
Expand Down
13 changes: 11 additions & 2 deletions src/modules/account/account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export class AccountService {

// ! verificar responsabilidade única
const hashedEmail = await this.hashData(email);

const account = await this.accountRepository.getCredentialIdByEmail(
hashedEmail,
);
Expand Down Expand Up @@ -189,7 +190,6 @@ export class AccountService {
});

delete account.password;

return {
url,
fullname: account.parentProfile.fullname,
Expand Down Expand Up @@ -244,7 +244,6 @@ export class AccountService {
pid: credential.parentProfile.id,
};
const user = {
pid: credential.parentProfile.id,
parentName: credential.parentProfile.fullname,
childrens: credential.parentProfile.childrens,
};
Expand All @@ -260,4 +259,14 @@ export class AccountService {
user,
};
}
async getCredential(id: string) {
const credential = await this.accountRepository.getCredentialId(id);
if (!credential) {
throw new EmailNotFoundException();
}

return {
credential,
};
}
}
45 changes: 45 additions & 0 deletions test/unit/account.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('AccountService unit test', () => {
.fn()
.mockReturnValue(stubs.getCredentialOutput),
savePasswordResetInformation: jest.fn(),
getCredentialId: jest.fn().mockReturnValue(stubs.getCredentialOutputById),
};

beforeEach(async () => {
Expand Down Expand Up @@ -94,4 +95,48 @@ describe('AccountService unit test', () => {
}
});
});
describe('Account', () => {
it('Happy path - should return account details', async () => {
const actual = await service.getCredential(
stubs.getCredentialOutputById.id,
);

expect(actual.credential).toHaveProperty(
'message',
'Dados recebidos com sucesso',
);
expect(actual).toHaveProperty('credential');
expect(actual.credential).toHaveProperty(
'id',
stubs.getCredentialOutputById.id,
);
expect(actual.credential).toHaveProperty(
'email',
stubs.getCredentialOutputById.email,
);
expect(actual.credential).toHaveProperty('parentProfile');
expect(actual.credential.parentProfile).toHaveProperty(
'id',
stubs.getCredentialOutputById.parentProfile.id,
);
expect(actual.credential.parentProfile).toHaveProperty(
'fullname',
stubs.getCredentialOutputById.parentProfile.fullname,
);
expect(actual.credential.parentProfile).toHaveProperty('childrens');
expect(actual.credential.parentProfile.childrens).toHaveLength(1);
});
});

it('Unhappy path - should return void', async () => {
jest
.spyOn(accountRepositoryMock, 'getCredentialId')
.mockReturnValueOnce(null);

try {
await service.getCredential(stubs.getCredentialOutputById.id);
} catch (actual) {
expect(actual).toBeInstanceOf(EmailNotFoundException);
}
});
});
19 changes: 18 additions & 1 deletion test/unit/account.service.stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const resetPasswordInput: ResetPasswordDto = {
};

export const getCredentialOutput: GetCredentialIdByEmailOutput = {
id: faker.helpers.rangeToNumber({ min: 1, max: 3000 }),
id: faker.string.uuid(),
password: faker.internet.password(),
parentProfile: {
id: faker.string.uuid(),
Expand All @@ -36,3 +36,20 @@ export const getCredentialOutput: GetCredentialIdByEmailOutput = {
],
},
};
export const getCredentialOutputById = {
message: 'Dados recebidos com sucesso',
id: faker.string.uuid(),
email: faker.internet.email(),
parentProfile: {
id: faker.string.uuid(),
fullname: faker.person.fullName(),
childrens: [
{
id: faker.number.int(),
fullname: faker.person.fullName(),
birthdate: faker.date.birthdate(),
gender: faker.helpers.enumValue(Genders),
},
],
},
};
Loading