@tmlmobilidade/controllers 20260128.2248.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/agencies/agencies.d.ts +20 -0
- package/dist/agencies/agencies.js +27 -0
- package/dist/agencies/index.d.ts +1 -0
- package/dist/agencies/index.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/rides/index.d.ts +1 -0
- package/dist/rides/index.js +1 -0
- package/dist/rides/rides.d.ts +18 -0
- package/dist/rides/rides.js +98 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type FastifyReply, type FastifyRequest } from '@tmlmobilidade/fastify';
|
|
2
|
+
import { type Agency } from '@tmlmobilidade/types';
|
|
3
|
+
export declare class AgenciesSharedController {
|
|
4
|
+
/**
|
|
5
|
+
* Returns all Agencies sorted by ID.
|
|
6
|
+
* @param request The request object
|
|
7
|
+
* @param reply The reply object
|
|
8
|
+
*/
|
|
9
|
+
static getAll(request: FastifyRequest, reply: FastifyReply<Agency[]>): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Returns an Agency by ID.
|
|
12
|
+
* @param request The request object
|
|
13
|
+
* @param reply The reply object
|
|
14
|
+
*/
|
|
15
|
+
static getById(request: FastifyRequest<{
|
|
16
|
+
Params: {
|
|
17
|
+
id: string;
|
|
18
|
+
};
|
|
19
|
+
}>, reply: FastifyReply<Agency>): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { HttpException, HttpStatus } from '@tmlmobilidade/consts';
|
|
3
|
+
import { agencies } from '@tmlmobilidade/interfaces';
|
|
4
|
+
/* * */
|
|
5
|
+
export class AgenciesSharedController {
|
|
6
|
+
//
|
|
7
|
+
/**
|
|
8
|
+
* Returns all Agencies sorted by ID.
|
|
9
|
+
* @param request The request object
|
|
10
|
+
* @param reply The reply object
|
|
11
|
+
*/
|
|
12
|
+
static async getAll(request, reply) {
|
|
13
|
+
const allAgencies = await agencies.findMany({}, { sort: { _id: 1 } });
|
|
14
|
+
reply.send({ data: allAgencies, error: null, statusCode: HttpStatus.OK });
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Returns an Agency by ID.
|
|
18
|
+
* @param request The request object
|
|
19
|
+
* @param reply The reply object
|
|
20
|
+
*/
|
|
21
|
+
static async getById(request, reply) {
|
|
22
|
+
const agencyData = await agencies.findById(request.params.id);
|
|
23
|
+
if (!agencyData)
|
|
24
|
+
throw new HttpException(HttpStatus.NOT_FOUND, 'Agency not found');
|
|
25
|
+
reply.send({ data: agencyData, error: null, statusCode: HttpStatus.OK });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './agencies.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './agencies.js';
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rides.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './rides.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type FastifyReply, type FastifyRequest } from '@tmlmobilidade/fastify';
|
|
2
|
+
import { type ActionsOf, type GetRidesBatchQuery, type Permission, type RideNormalized } from '@tmlmobilidade/types';
|
|
3
|
+
export declare class RidesSharedController {
|
|
4
|
+
/**
|
|
5
|
+
* Gets a batch of Rides built with an aggregation pipeline.
|
|
6
|
+
* @param request The Fastify request object.
|
|
7
|
+
* @param reply The Fastify reply object.
|
|
8
|
+
*/
|
|
9
|
+
static getBatch<S extends Permission['scope']>(request: FastifyRequest<{
|
|
10
|
+
Querystring: GetRidesBatchQuery;
|
|
11
|
+
}>, reply: FastifyReply<RideNormalized[]>, scope: S, action: ActionsOf<S>): Promise<never>;
|
|
12
|
+
/**
|
|
13
|
+
* Get a Ride by ID.
|
|
14
|
+
* @param request The Fastify request object.
|
|
15
|
+
* @param reply The Fastify reply object.
|
|
16
|
+
*/
|
|
17
|
+
static getRideById<S extends Permission['scope']>(request: FastifyRequest, reply: FastifyReply<RideNormalized>, scope: S, action: ActionsOf<S>): Promise<never>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { HttpStatus } from '@tmlmobilidade/consts';
|
|
3
|
+
import { rides, ridesBatchAggregationPipeline } from '@tmlmobilidade/interfaces';
|
|
4
|
+
import { normalizeRide } from '@tmlmobilidade/normalizers';
|
|
5
|
+
import { GetRidesBatchQuerySchema, PermissionCatalog } from '@tmlmobilidade/types';
|
|
6
|
+
/* * */
|
|
7
|
+
export class RidesSharedController {
|
|
8
|
+
//
|
|
9
|
+
/**
|
|
10
|
+
* Gets a batch of Rides built with an aggregation pipeline.
|
|
11
|
+
* @param request The Fastify request object.
|
|
12
|
+
* @param reply The Fastify reply object.
|
|
13
|
+
*/
|
|
14
|
+
static async getBatch(request, reply, scope, action) {
|
|
15
|
+
//
|
|
16
|
+
//
|
|
17
|
+
// Validate the request query parameters
|
|
18
|
+
const parsedQuery = GetRidesBatchQuerySchema.parse(request.query);
|
|
19
|
+
console.log('RidesSharedController.getBatch - parsedQuery:', parsedQuery);
|
|
20
|
+
//
|
|
21
|
+
// Detect which agency_ids the user has access to,
|
|
22
|
+
// based on their permissions. If none, return an empty array.
|
|
23
|
+
const ridesPermission = PermissionCatalog.get(request.permissions, scope, action);
|
|
24
|
+
if (!ridesPermission['resources']?.agency_ids?.length)
|
|
25
|
+
return reply.send({ data: [], error: null, statusCode: HttpStatus.OK });
|
|
26
|
+
const allowAllAgencies = ridesPermission['resources'].agency_ids.includes(PermissionCatalog.ALLOW_ALL_FLAG);
|
|
27
|
+
//
|
|
28
|
+
// If search is provided, immediately try to find the ride by ID.
|
|
29
|
+
// If found, return it as the only result. This optimizes
|
|
30
|
+
// for the common case of searching by ride ID.
|
|
31
|
+
const searchQuery = parsedQuery.search?.trim() ?? '';
|
|
32
|
+
const foundRideById = await rides.findOne({
|
|
33
|
+
_id: searchQuery,
|
|
34
|
+
...(allowAllAgencies ? {} : { agency_id: { $in: ridesPermission['resources'].agency_ids } }),
|
|
35
|
+
});
|
|
36
|
+
if (foundRideById) {
|
|
37
|
+
const normalizedRide = normalizeRide(foundRideById);
|
|
38
|
+
return reply.send({ data: [normalizedRide], error: null, statusCode: HttpStatus.OK });
|
|
39
|
+
}
|
|
40
|
+
//
|
|
41
|
+
// Get the rides batch using native MongoDB cursor
|
|
42
|
+
// with batchSize to prevent memory issues
|
|
43
|
+
const pipeline = ridesBatchAggregationPipeline({
|
|
44
|
+
agency_ids: parsedQuery.agency_ids?.filter(id => allowAllAgencies || ridesPermission['resources'].agency_ids.includes(id)) ?? [],
|
|
45
|
+
date_end: parsedQuery.date_end,
|
|
46
|
+
date_start: parsedQuery.date_start,
|
|
47
|
+
delay_statuses: parsedQuery.delay_statuses,
|
|
48
|
+
line_ids: parsedQuery.line_ids,
|
|
49
|
+
operational_statuses: parsedQuery.operational_statuses,
|
|
50
|
+
search: parsedQuery.search,
|
|
51
|
+
seen_statuses: parsedQuery.seen_statuses,
|
|
52
|
+
stop_ids: parsedQuery.stop_ids,
|
|
53
|
+
});
|
|
54
|
+
//
|
|
55
|
+
// Limit the number of rides to 2000 and sort by start_time_scheduled
|
|
56
|
+
pipeline.push({ $limit: 2000 }, { $sort: { start_time_scheduled: 1 } });
|
|
57
|
+
//
|
|
58
|
+
// Fetch the rides batch from the database
|
|
59
|
+
const ridesBatch = await rides.aggregate(pipeline);
|
|
60
|
+
console.log('RidesSharedController.getBatch - ridesBatch count:', ridesBatch?.length ?? 0);
|
|
61
|
+
//
|
|
62
|
+
// Send the response
|
|
63
|
+
reply.send({
|
|
64
|
+
data: ridesBatch ?? [],
|
|
65
|
+
error: null,
|
|
66
|
+
statusCode: HttpStatus.OK,
|
|
67
|
+
});
|
|
68
|
+
//
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get a Ride by ID.
|
|
72
|
+
* @param request The Fastify request object.
|
|
73
|
+
* @param reply The Fastify reply object.
|
|
74
|
+
*/
|
|
75
|
+
static async getRideById(request, reply, scope, action) {
|
|
76
|
+
//
|
|
77
|
+
//
|
|
78
|
+
// Detect which agency_ids the user has access to,
|
|
79
|
+
// based on their permissions. If none, return an empty array.
|
|
80
|
+
const ridesPermission = PermissionCatalog.get(request.permissions, scope, action);
|
|
81
|
+
if (!ridesPermission['resources']?.agency_ids?.length)
|
|
82
|
+
return reply.send({ data: null, error: null, statusCode: HttpStatus.OK });
|
|
83
|
+
const allowAllAgencies = ridesPermission['resources'].agency_ids.includes(PermissionCatalog.ALLOW_ALL_FLAG);
|
|
84
|
+
//
|
|
85
|
+
// If search is provided, immediately try to find the ride by ID.
|
|
86
|
+
// If found, return it as the only result. This optimizes
|
|
87
|
+
// for the common case of searching by ride ID.
|
|
88
|
+
const foundRideById = await rides.findOne({
|
|
89
|
+
_id: request.params['id'],
|
|
90
|
+
...(allowAllAgencies ? {} : { agency_id: { $in: ridesPermission['resources'].agency_ids } }),
|
|
91
|
+
});
|
|
92
|
+
if (foundRideById) {
|
|
93
|
+
const normalizedRide = normalizeRide(foundRideById);
|
|
94
|
+
return reply.send({ data: normalizedRide, error: null, statusCode: HttpStatus.OK });
|
|
95
|
+
}
|
|
96
|
+
//
|
|
97
|
+
}
|
|
98
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tmlmobilidade/controllers",
|
|
3
|
+
"version": "20260128.2248.28",
|
|
4
|
+
"author": {
|
|
5
|
+
"email": "iso@tmlmobilidade.pt",
|
|
6
|
+
"name": "TML-ISO"
|
|
7
|
+
},
|
|
8
|
+
"license": "AGPL-3.0-or-later",
|
|
9
|
+
"homepage": "https://github.com/tmlmobilidade/services#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/tmlmobilidade/services/issues"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/tmlmobilidade/services.git"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"public transit",
|
|
19
|
+
"tml",
|
|
20
|
+
"transportes metropolitanos de lisboa",
|
|
21
|
+
"services"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsc && resolve-tspaths",
|
|
34
|
+
"lint": "eslint && tsc --noEmit",
|
|
35
|
+
"lint:fix": "eslint --fix",
|
|
36
|
+
"watch": "tsc-watch --onSuccess 'resolve-tspaths'"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@tmlmobilidade/consts": "*",
|
|
40
|
+
"@tmlmobilidade/fastify": "*",
|
|
41
|
+
"@tmlmobilidade/interfaces": "*",
|
|
42
|
+
"@tmlmobilidade/normalizers": "*",
|
|
43
|
+
"@tmlmobilidade/utils": "*",
|
|
44
|
+
"zod": "3.25.76"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@tmlmobilidade/tsconfig": "*",
|
|
48
|
+
"@tmlmobilidade/types": "*",
|
|
49
|
+
"@types/node": "25.1.0",
|
|
50
|
+
"resolve-tspaths": "0.8.23",
|
|
51
|
+
"tsc-watch": "7.2.0",
|
|
52
|
+
"typescript": "5.9.3"
|
|
53
|
+
}
|
|
54
|
+
}
|