Skip to content

Commit d18abb7

Browse files
chore: merge main
2 parents ee9606c + e4d29bc commit d18abb7

10 files changed

+428
-230
lines changed

CHANGELOG.md

Lines changed: 202 additions & 202 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@hivetown/backend",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Hivetown Backend",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/controllers/producers.ts

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { Authentication } from '../external/Authentication';
1919
import { hasPermissions } from '../utils/hasPermission';
2020
import type { ProductionUnitFilters } from '../interfaces/ProductionUnitFilters';
2121
import { StringSearchType } from '../enums/StringSearchType';
22+
import type { CarrierFilters } from '../interfaces/CarrierFilters';
2223

2324
@Controller('/producers')
2425
@Injectable()
@@ -926,15 +927,16 @@ export class ProducersController {
926927
return res.status(200).json(products);
927928
}
928929

929-
@Get('/:producerId/units/:unitId/carriers/inTransit', [
930+
@Get('/:producerId/units/:unitId/carriers', [
930931
validate({
931932
params: Joi.object({
932933
producerId: Joi.number().required(),
933934
unitId: Joi.number().required()
934935
}),
935936
query: Joi.object({
936937
page: Joi.number().optional(),
937-
pageSize: Joi.number().optional()
938+
pageSize: Joi.number().optional(),
939+
status: Joi.string().valid('Available', 'Unavailable').optional()
938940
})
939941
}),
940942
authenticationMiddleware,
@@ -952,24 +954,29 @@ export class ProducersController {
952954
]
953955
})
954956
])
955-
public async getProductionUnitCarriersInTransitOfProductionUnit(
957+
public async getProductionUnitCarriers(
956958
@Response() res: Express.Response,
957-
@Request() req: Express.Request,
958959
@Params('producerId') producerId: number,
959-
@Params('unitId') unitId: number
960+
@Params('unitId') unitId: number,
961+
@Request() req: Express.Request
960962
) {
961-
const producer = await container.producerGateway.findById(producerId);
963+
const producer = await container.producerGateway.findByIdWithUnits(producerId);
962964
if (!producer) throw new NotFoundError('Producer not found');
963965

964-
const productionUnit = await container.productionUnitGateway.findById(unitId);
965-
if (!productionUnit || productionUnit.producer.user.id !== producer.user.id) throw new NotFoundError('Production unit not found');
966+
const productionUnit = producer.productionUnits.getItems().find((unit) => unit.id === Number(unitId));
967+
if (!productionUnit) throw new NotFoundError('Production unit not found for this producer');
966968

967969
const options: PaginatedOptions = {
968970
page: Number(req.query.page) || -1,
969971
size: Number(req.query.pageSize) || -1
970972
};
971973

972-
const carriers = await container.carrierGateway.findAllinTranstit(productionUnit.id, options);
974+
const filters: CarrierFilters = {
975+
productionUnitId: productionUnit.id,
976+
status: req.query.status === 'Available' || req.query.status === 'Unavailable' ? req.query.status : undefined
977+
};
978+
979+
const carriers = await container.carrierGateway.findFromProductionUnit(filters, options);
973980

974981
return res.status(200).json(carriers);
975982
}

src/gateways/CarrierGateway.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { EntityRepository, MikroORM } from '@mikro-orm/mysql';
33
import type { BaseItems } from '../interfaces/BaseItems';
44
import type { PaginatedOptions } from '../interfaces/PaginationOptions';
55
import { paginate } from '../utils/paginate';
6+
import type { CarrierFilters } from '../interfaces/CarrierFilters';
67

78
export class CarrierGateway {
89
private repository: EntityRepository<Carrier>;
@@ -11,24 +12,31 @@ export class CarrierGateway {
1112
this.repository = orm.em.getRepository(Carrier);
1213
}
1314

14-
public async findAllinTranstit(productionUnitId: number, options: PaginatedOptions): Promise<BaseItems<Carrier>> {
15-
const pagination = paginate(options);
16-
const [carriers, totalResults] = await Promise.all([
17-
this.repository.find(
18-
{ productionUnit: productionUnitId, status: 'UNAVAILABLE', deletedAt: null },
19-
{
20-
populate: ['productionUnit'],
21-
limit: pagination.limit,
22-
offset: pagination.offset
23-
}
24-
),
25-
this.repository.count({ productionUnit: productionUnitId, status: 'UNAVAILABLE', deletedAt: null })
26-
]);
15+
public async findFromProductionUnit(filters: CarrierFilters, options: PaginatedOptions): Promise<BaseItems<Carrier>> {
16+
const paginataion = paginate(options);
17+
const qb = this.repository
18+
.createQueryBuilder('c')
19+
.select('*')
20+
.where({ productionUnit: { id: filters.productionUnitId }, deletedAt: null })
21+
.leftJoinAndSelect('c.image', 'ci');
22+
23+
if (filters.status) {
24+
void qb.andWhere({ status: filters.status });
25+
}
26+
27+
const totalItemsQb = qb.clone();
28+
29+
// Paginate
30+
void qb.offset(paginataion.offset).limit(paginataion.limit);
31+
32+
// Fetch results and map them
33+
const [totalResults, carriers] = await Promise.all([totalItemsQb.getCount(), qb.getResultList()]);
34+
2735
return {
2836
items: carriers,
2937
totalItems: totalResults,
30-
totalPages: Math.ceil(totalResults / pagination.limit),
31-
page: Math.ceil(pagination.offset / pagination.limit) + 1,
38+
totalPages: Math.ceil(totalResults / paginataion.limit),
39+
page: Math.ceil(paginataion.offset / paginataion.limit) + 1,
3240
pageSize: carriers.length
3341
};
3442
}

src/gateways/ProductionUnitGateway.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export class ProductionUnitGateway {
3030
.createQueryBuilder('pu')
3131
.select('*')
3232
.where({ producer: { id: filter.producerId }, deletedAt: null })
33-
.leftJoinAndSelect('pu.address', 'pa');
33+
.leftJoinAndSelect('pu.address', 'pa')
34+
.leftJoinAndSelect('pu.images', 'pi');
3435

3536
if (filter.search) {
3637
void qb.andWhere({

src/interfaces/CarrierFilters.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { CarrierStatus } from '../enums';
2+
3+
export interface CarrierFilters {
4+
productionUnitId?: number;
5+
status?: keyof typeof CarrierStatus;
6+
}

src/utils/paginate.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,5 @@ export const paginate = (options: PaginatedOptions = { page: 1, size: 24 }, max
1010

1111
const offset = (page - 1) * size;
1212
const limit = size;
13-
1413
return { offset, limit };
1514
};

tests/hasPermissions.test.ts

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import type { User } from '../src/entities/User';
2+
import { Permission } from '../src/enums/Permission';
3+
import { UserType } from '../src/enums/UserType';
4+
import { hasPermissions } from '../src/utils/hasPermission';
5+
6+
let user: User; // Variável para armazenar o usuário
7+
8+
beforeAll(() => {
9+
user = {
10+
id: 1,
11+
authId: '123',
12+
name: 'John Doe',
13+
email: 'johnD@gmail.com',
14+
phone: '912345678',
15+
vat: '123456789',
16+
type: UserType.Consumer,
17+
disableEmails: false
18+
};
19+
20+
return user;
21+
});
22+
23+
test('no permissions user example', () => {
24+
const noPermissions = hasPermissions(user, Permission.READ_OTHER_CONSUMER);
25+
expect(noPermissions).toBe(false);
26+
});
27+
28+
test('read/write other consumer permission example', () => {
29+
const role = {
30+
id: 1,
31+
name: 'AccountManager',
32+
permissions: Permission.READ_OTHER_CONSUMER
33+
};
34+
35+
user.role = role;
36+
37+
const readOtherConsumer = hasPermissions(user, Permission.READ_OTHER_CONSUMER);
38+
const writeOtherConsumer = hasPermissions(user, Permission.WRITE_OTHER_CONSUMER);
39+
40+
const readOtherProducer = hasPermissions(user, Permission.READ_OTHER_PRODUCER);
41+
const writeOtherProducer = hasPermissions(user, Permission.WRITE_OTHER_PRODUCER);
42+
43+
expect(readOtherConsumer).toBe(true);
44+
expect(writeOtherConsumer).toBe(false);
45+
46+
expect(readOtherProducer).toBe(false);
47+
expect(writeOtherProducer).toBe(false);
48+
});
49+
50+
test('read/write other user (consumero or producer) permission example', () => {
51+
const role = {
52+
id: 2,
53+
name: 'AccountEditor',
54+
permissions:
55+
Permission.READ_OTHER_CONSUMER | Permission.WRITE_OTHER_CONSUMER | Permission.READ_OTHER_PRODUCER | Permission.WRITE_OTHER_PRODUCER
56+
};
57+
58+
user.role = role;
59+
60+
const readOtherConsumer = hasPermissions(user, Permission.READ_OTHER_CONSUMER);
61+
const writeOtherConsumer = hasPermissions(user, Permission.WRITE_OTHER_CONSUMER);
62+
63+
const readOtherProducer = hasPermissions(user, Permission.READ_OTHER_PRODUCER);
64+
const writeOtherProducer = hasPermissions(user, Permission.WRITE_OTHER_PRODUCER);
65+
66+
const writeCategory = hasPermissions(user, Permission.WRITE_CATEGORY);
67+
68+
expect(readOtherConsumer).toBe(true);
69+
expect(writeOtherConsumer).toBe(true);
70+
71+
expect(readOtherProducer).toBe(true);
72+
expect(writeOtherProducer).toBe(true);
73+
74+
expect(writeCategory).toBe(false);
75+
});
76+
77+
test('all permissions user example', () => {
78+
const role = {
79+
id: 3,
80+
name: 'Admin',
81+
permissions: Permission.ALL
82+
};
83+
84+
user.role = role;
85+
86+
const readOtherConsumer = hasPermissions(user, Permission.READ_OTHER_CONSUMER);
87+
const writeOtherConsumer = hasPermissions(user, Permission.WRITE_OTHER_CONSUMER);
88+
89+
const readOtherProducer = hasPermissions(user, Permission.READ_OTHER_PRODUCER);
90+
const writeOtherProducer = hasPermissions(user, Permission.WRITE_OTHER_PRODUCER);
91+
92+
const writeCategory = hasPermissions(user, Permission.WRITE_CATEGORY);
93+
const deleteCategory = hasPermissions(user, Permission.DELETE_CATEGORY);
94+
95+
const writeProduct = hasPermissions(user, Permission.WRITE_PRODUCT);
96+
const deleteProduct = hasPermissions(user, Permission.DELETE_PRODUCT);
97+
98+
const createAdmin = hasPermissions(user, Permission.CREATE_ADMIN);
99+
const deleteAdmin = hasPermissions(user, Permission.DELETE_ADMIN);
100+
101+
expect(readOtherConsumer).toBe(true);
102+
expect(writeOtherConsumer).toBe(true);
103+
104+
expect(readOtherProducer).toBe(true);
105+
expect(writeOtherProducer).toBe(true);
106+
107+
expect(writeCategory).toBe(true);
108+
expect(deleteCategory).toBe(true);
109+
110+
expect(writeProduct).toBe(true);
111+
expect(deleteProduct).toBe(true);
112+
113+
expect(createAdmin).toBe(true);
114+
expect(deleteAdmin).toBe(true);
115+
});

tests/paginate.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { paginate } from '../src/utils/paginate';
2+
import type { PaginatedOptions } from '../src/interfaces/PaginationOptions';
3+
4+
test('valid paginated example', () => {
5+
const options: PaginatedOptions = {
6+
page: 3,
7+
size: 10
8+
};
9+
10+
const result = paginate(options);
11+
12+
expect(result.limit).toEqual(10);
13+
expect(result.offset).toEqual(20);
14+
});
15+
16+
test('invalid paginated example - negative page', () => {
17+
const options: PaginatedOptions = {
18+
page: -3,
19+
size: 10
20+
};
21+
22+
const result = paginate(options);
23+
24+
expect(result.limit).toEqual(10);
25+
expect(result.offset).toEqual(0);
26+
});
27+
28+
test('invalid paginated example - negative size', () => {
29+
const options: PaginatedOptions = {
30+
page: 3,
31+
size: -10
32+
};
33+
34+
const result = paginate(options);
35+
36+
expect(result.limit).toEqual(1);
37+
expect(result.offset).toEqual(2);
38+
});
39+
40+
test('invalid paginated example - negative page and size', () => {
41+
const options: PaginatedOptions = {
42+
page: -3,
43+
size: -10
44+
};
45+
46+
const result = paginate(options);
47+
48+
expect(result.limit).toEqual(1);
49+
expect(result.offset).toEqual(0);
50+
});
51+
52+
test('invalid paginated example - size too big', () => {
53+
const options: PaginatedOptions = {
54+
page: 10,
55+
size: 1000
56+
};
57+
58+
const result = paginate(options);
59+
60+
expect(result.limit).toEqual(100);
61+
expect(result.offset).toEqual(900);
62+
});

tests/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"extends": "../tsconfig.base.json",
33
"compilerOptions": {
44
"outDir": "../dist/tests",
5-
"rootDir": ".",
5+
"rootDir": "../",
66
"types": ["node", "jest"]
77
}
88
}

0 commit comments

Comments
 (0)