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

Salvar nos eventos o histórico de alterações de username #1727

Merged
merged 2 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions models/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,7 @@ function validateObject(object) {
return cleanObject;
}

async function findAll() {
const results = await database.query('SELECT * FROM events;');
return results.rows;
}

export default Object.freeze({
create,
updateMetadata,
findAll,
});
4 changes: 2 additions & 2 deletions pages/api/v1/contents/[username]/[slug]/index.public.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async function patchHandler(request, response) {
});
}

if (!unfilteredBodyValues.parent_id) {
if (!contentToBeUpdated.parent_id) {
if (!authorization.can(userTryingToPatch, 'create:content:text_root')) {
throw new ForbiddenError({
message: 'Você não possui permissão para editar conteúdos na raiz do site.',
Expand Down Expand Up @@ -147,7 +147,7 @@ async function patchHandler(request, response) {

const currentEvent = await event.create(
{
type: filteredBodyValues.parent_id ? 'update:content:text_child' : 'update:content:text_root',
type: contentToBeUpdated.parent_id ? 'update:content:text_child' : 'update:content:text_root',
aprendendofelipe marked this conversation as resolved.
Show resolved Hide resolved
originatorUserId: request.context.user.id,
originatorIp: request.context.clientIp,
},
Expand Down
7 changes: 7 additions & 0 deletions pages/api/v1/users/[username]/index.public.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,13 @@ async function patchHandler(request, response) {
for (const field of updatableFields) {
if (originalUser[field] !== updatedUser[field]) {
metadata.updatedFields.push(field);

if (field === 'username') {
metadata.username = {
old: originalUser.username,
new: updatedUser.username,
};
}
}
}

Expand Down
168 changes: 168 additions & 0 deletions tests/integration/api/v1/contents/[username]/[slug]/patch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,174 @@ describe('PATCH /api/v1/contents/[username]/[slug]', () => {
});
});

describe('User without "create:content:text_root" feature', () => {
test('"root" content with valid data', async () => {
const contentsRequestBuilder = new RequestBuilder('/api/v1/contents');
const userWithoutFeature = await contentsRequestBuilder.buildUser({ without: ['create:content:text_root'] });

const rootContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
title: 'Root content title',
body: 'Root content body',
});

const { response, responseBody } = await contentsRequestBuilder.patch(
`/${userWithoutFeature.username}/${rootContent.slug}`,
{
title: 'Valid user trying to update "root" content.',
body: "He shouldn't be able to do it because he lacks the 'create:content:text_root' feature.",
},
);

expect(response.status).toEqual(403);
expect(responseBody.status_code).toEqual(403);
expect(responseBody.name).toEqual('ForbiddenError');
expect(responseBody.message).toEqual('Você não possui permissão para editar conteúdos na raiz do site.');
expect(responseBody.action).toEqual('Verifique se você possui a feature "create:content:text_root".');
expect(uuidVersion(responseBody.error_id)).toEqual(4);
expect(uuidVersion(responseBody.request_id)).toEqual(4);
expect(responseBody.error_location_code).toEqual(
'CONTROLLER:CONTENT:PATCH_HANDLER:CREATE:CONTENT:TEXT_ROOT:FEATURE_NOT_FOUND',
);
});

test('"child" content with valid data', async () => {
const contentsRequestBuilder = new RequestBuilder('/api/v1/contents');
const userWithoutFeature = await contentsRequestBuilder.buildUser({ without: ['create:content:text_root'] });

const rootContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
title: 'Root content title',
body: 'Root content body',
});

const childContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
body: 'Child content with original body',
parent_id: rootContent.id,
status: 'published',
});

const { response, responseBody } = await contentsRequestBuilder.patch(
`/${userWithoutFeature.username}/${childContent.slug}`,
{
body: 'Updated body, even without "create:content:text_root" feature.',
},
);

expect(response.status).toEqual(200);

expect(responseBody).toStrictEqual({
id: responseBody.id,
owner_id: userWithoutFeature.id,
parent_id: rootContent.id,
slug: childContent.slug,
title: null,
body: 'Updated body, even without "create:content:text_root" feature.',
status: 'published',
source_url: null,
created_at: responseBody.created_at,
updated_at: responseBody.updated_at,
published_at: responseBody.published_at,
deleted_at: null,
tabcoins: 0,
tabcoins_credit: 0,
tabcoins_debit: 0,
owner_username: userWithoutFeature.username,
});

expect(uuidVersion(responseBody.id)).toEqual(4);
expect(Date.parse(responseBody.created_at)).not.toEqual(NaN);
expect(Date.parse(responseBody.published_at)).not.toEqual(NaN);
expect(Date.parse(responseBody.updated_at)).not.toEqual(NaN);
expect(responseBody.updated_at > childContent.updated_at.toISOString()).toEqual(true);
});
});

describe('User without "create:content:text_child" feature', () => {
test('"root" content with valid data', async () => {
const contentsRequestBuilder = new RequestBuilder('/api/v1/contents');
const userWithoutFeature = await contentsRequestBuilder.buildUser({ without: ['create:content:text_child'] });

const rootContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
title: 'Valid user trying to update "root" content.',
body: 'It should be possible, even without the "create:content:text_child" feature.',
status: 'published',
});

const { response, responseBody } = await contentsRequestBuilder.patch(
`/${userWithoutFeature.username}/${rootContent.slug}`,
{ source_url: 'http://www.tabnews.com.br/' },
);

expect(response.status).toEqual(200);

expect(responseBody).toStrictEqual({
id: responseBody.id,
owner_id: userWithoutFeature.id,
parent_id: null,
slug: 'valid-user-trying-to-update-root-content',
title: 'Valid user trying to update "root" content.',
body: 'It should be possible, even without the "create:content:text_child" feature.',
status: 'published',
source_url: 'http://www.tabnews.com.br/',
created_at: responseBody.created_at,
updated_at: responseBody.updated_at,
published_at: responseBody.published_at,
deleted_at: null,
tabcoins: 1,
tabcoins_credit: 0,
tabcoins_debit: 0,
owner_username: userWithoutFeature.username,
});

expect(uuidVersion(responseBody.id)).toEqual(4);
expect(Date.parse(responseBody.created_at)).not.toEqual(NaN);
expect(Date.parse(responseBody.published_at)).not.toEqual(NaN);
expect(Date.parse(responseBody.updated_at)).not.toEqual(NaN);
expect(responseBody.updated_at > rootContent.updated_at.toISOString()).toEqual(true);
});

test('"child" content with valid data', async () => {
const contentsRequestBuilder = new RequestBuilder('/api/v1/contents');
const userWithoutFeature = await contentsRequestBuilder.buildUser({ without: ['create:content:text_child'] });

const rootContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
title: 'Root content title',
body: 'Root content body',
});

const childContent = await orchestrator.createContent({
owner_id: userWithoutFeature.id,
body: 'Child content body',
parent_id: rootContent.id,
});

const { response, responseBody } = await contentsRequestBuilder.patch(
`/${userWithoutFeature.username}/${childContent.slug}`,
{
title: 'Valid user, trying to update "child" content.',
body: "He shouldn't be able to do it because he lacks the 'create:content:text_child' feature.",
},
);

expect(response.status).toEqual(403);
expect(responseBody.status_code).toEqual(403);
expect(responseBody.name).toEqual('ForbiddenError');
expect(responseBody.message).toEqual(
'Você não possui permissão para editar conteúdos dentro de outros conteúdos.',
);
expect(responseBody.action).toEqual('Verifique se você possui a feature "create:content:text_child".');
expect(uuidVersion(responseBody.error_id)).toEqual(4);
expect(uuidVersion(responseBody.request_id)).toEqual(4);
expect(responseBody.error_location_code).toEqual(
'CONTROLLER:CONTENT:PATCH_HANDLER:CREATE:CONTENT:TEXT_CHILD:FEATURE_NOT_FOUND',
);
});
});

describe('Default user', () => {
test('Content without PATCH Body and "Content-Type"', async () => {
const contentsRequestBuilder = new RequestBuilder('/api/v1/contents');
Expand Down
61 changes: 34 additions & 27 deletions tests/integration/api/v1/contents/firewall.post.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { version as uuidVersion } from 'uuid';

import content from 'models/content.js';
import event from 'models/event.js';
import orchestrator from 'tests/orchestrator.js';

beforeEach(async () => {
Expand Down Expand Up @@ -61,9 +60,9 @@ describe('POST /api/v1/contents [FIREWALL]', () => {
const request2Body = await request2.json();
const request3Body = await request3.json();

expect(request1.status).toBe(201);
expect(request2.status).toBe(201);
expect(request3.status).toBe(429);
expect.soft(request1.status).toBe(201);
expect.soft(request2.status).toBe(201);
expect.soft(request3.status).toBe(429);

expect(request3Body).toStrictEqual({
name: 'TooManyRequestsError',
Expand Down Expand Up @@ -96,18 +95,22 @@ describe('POST /api/v1/contents [FIREWALL]', () => {
expect(content2.status).toStrictEqual('draft');
expect(content3).toStrictEqual(undefined);

const events = await event.findAll();
expect(events.length).toEqual(3);
const lastEvent = await orchestrator.getLastEvent();

expect(uuidVersion(events[2].id)).toEqual(4);
expect(events[2].type).toEqual('firewall:block_contents:text_root');
expect(events[2].originator_user_id).toEqual(defaultUser.id);
expect(events[2].originator_ip).toEqual('127.0.0.1');
expect(events[2].metadata).toEqual({
from_rule: 'create:content:text_root',
contents: [content1.id, content2.id],
expect(lastEvent).toStrictEqual({
id: lastEvent.id,
type: 'firewall:block_contents:text_root',
originator_user_id: defaultUser.id,
originator_ip: '127.0.0.1',
metadata: {
from_rule: 'create:content:text_root',
contents: [content1.id, content2.id],
},
created_at: lastEvent.created_at,
});
expect(Date.parse(events[2].created_at)).not.toEqual(NaN);

expect(uuidVersion(lastEvent.id)).toBe(4);
expect(Date.parse(lastEvent.created_at)).not.toBe(NaN);
});

test('Spamming valid "child" contents', async () => {
Expand Down Expand Up @@ -176,9 +179,9 @@ describe('POST /api/v1/contents [FIREWALL]', () => {
const request2Body = await request2.json();
const request3Body = await request3.json();

expect(request1.status).toBe(201);
expect(request2.status).toBe(201);
expect(request3.status).toBe(429);
expect.soft(request1.status).toBe(201);
expect.soft(request2.status).toBe(201);
expect.soft(request3.status).toBe(429);

expect(request3Body).toStrictEqual({
name: 'TooManyRequestsError',
Expand Down Expand Up @@ -211,18 +214,22 @@ describe('POST /api/v1/contents [FIREWALL]', () => {
expect(content2.status).toStrictEqual('draft');
expect(content3).toStrictEqual(undefined);

const events = await event.findAll();
expect(events.length).toEqual(4);
const lastEvent = await orchestrator.getLastEvent();

expect(uuidVersion(events[3].id)).toEqual(4);
expect(events[3].type).toEqual('firewall:block_contents:text_child');
expect(events[3].originator_user_id).toEqual(defaultUser.id);
expect(events[3].originator_ip).toEqual('127.0.0.1');
expect(events[3].metadata).toEqual({
from_rule: 'create:content:text_child',
contents: [content1.id, content2.id],
expect(lastEvent).toStrictEqual({
id: lastEvent.id,
type: 'firewall:block_contents:text_child',
originator_user_id: defaultUser.id,
originator_ip: '127.0.0.1',
metadata: {
from_rule: 'create:content:text_child',
contents: [content1.id, content2.id],
},
created_at: lastEvent.created_at,
});
expect(Date.parse(events[3].created_at)).not.toEqual(NaN);

expect(uuidVersion(lastEvent.id)).toBe(4);
expect(Date.parse(lastEvent.created_at)).not.toBe(NaN);
});
});
});
Loading
Loading