Migrated OCPI CPO Tokens endpoint
MODIFY
src/server/ocpi/OCPIServer.ts
src/server/ocpi/OCPIServer.ts
@@ -4,10 +4,10 @@ import { ServerAction, ServerType } from '../../types/Server';
import AppError from '../../exception/AppError';
import Constants from '../../utils/Constants';
import ExpressUtils from '../ExpressUtils';
+import GlobalRouter from './router/GlobalRouter';
import { HTTPError } from '../../types/HTTPError';
import Logging from '../../utils/Logging';
import OCPIEndpointStorage from '../../storage/mongodb/OCPIEndpointStorage';
-import OCPIGlobalRouter from './router/OCPIGlobalRouter';
import OCPIServiceConfiguration from '../../types/configuration/OCPIServiceConfiguration';
import OCPIServices from './OCPIServices';
import { OCPIStatusCode } from '../../types/ocpi/OCPIStatusCode';
@@ -36,7 +36,7 @@ export default class OCPIServer {
// Log Express Request
this.expressApplication.use(Logging.traceExpressRequest.bind(this));
// Routers
- this.expressApplication.use('/ocpi', new OCPIGlobalRouter().buildRoutes());
+ this.expressApplication.use('/ocpi', new GlobalRouter().buildRoutes());
// // New OCPI Services Instances
// const ocpiServices = new OCPIServices(this.ocpiRestConfig);
// // Register all services in express

MODIFY
src/server/ocpi/ocpi-services-impl/ocpi-2.1.1/CPOService.ts
src/server/ocpi/ocpi-services-impl/ocpi-2.1.1/CPOService.ts
@@ -3,7 +3,6 @@ import CPOCdrsEndpoint from './cpo/CPOCdrsEndpoint';
import CPOCommandsEndpoint from './cpo/CPOCommandsEndpoint';
import CPOSessionsEndpoint from './cpo/CPOSessionsEndpoint';
import CPOTariffsEndpoint from './cpo/CPOTariffsEndpoint';
-import CPOTokensEndpoint from './cpo/CPOTokensEndpoint';
import CredentialsEndpoint from './credentials/CredentialsEndpoint';
import OCPIServiceConfiguration from '../../../../types/configuration/OCPIServiceConfiguration';
@@ -15,7 +14,6 @@ export default class CPOService extends AbstractOCPIService {
super(ocpiRestConfig, CPOService.PATH, CPOService.VERSION);
// Register Endpoints
this.registerEndpoint(new CredentialsEndpoint(this));
- this.registerEndpoint(new CPOTokensEndpoint(this));
this.registerEndpoint(new CPOCommandsEndpoint(this));
this.registerEndpoint(new CPOSessionsEndpoint(this));
this.registerEndpoint(new CPOCdrsEndpoint(this));

RENAME
src/server/ocpi/router/OCPIGlobalRouter.ts
src/server/ocpi/router/GlobalRouter.ts
@@ -2,7 +2,7 @@ import CPORouter from './cpo/CPORouter';
import EMSPRouter from './emsp/EMSPRouter';
import express from 'express';
-export default class OCPIGlobalRouterV211 {
+export default class GlobalRouter {
private router: express.Router;
public constructor() {

MODIFY
src/server/ocpi/router/cpo/CPORouter.ts
src/server/ocpi/router/cpo/CPORouter.ts
import { OCPIServerRoute, ServerAction } from '../../../../types/Server';
import express, { NextFunction, Request, Response } from 'express';
+import CPOLocationsRouterV211 from './V2.1.1/CPOLocationsRouterV211';
+import CPOTokensRouterV211 from './V2.1.1/CPOTokensRouterV211';
import CPOVersionsService from '../../service/cpo/CPOVersionsService';
-import OCPICPOV211Router from './V2.1.1/OCPICPOV211Router';
import RouterUtils from '../../../../utils/RouterUtils';
export default class CPORouter {
@@ -26,6 +27,9 @@ export default class CPORouter {
}
protected buildRouteCpoV211(): void {
- this.router.use('/2.1.1', new OCPICPOV211Router().buildRoutes());
+ this.router.use('/2.1.1', [
+ new CPOLocationsRouterV211().buildRoutes(),
+ new CPOTokensRouterV211().buildRoutes(),
+ ]);
}
}

RENAME
src/server/ocpi/router/cpo/V2.1.1/OCPICPOV211Router.ts
src/server/ocpi/router/cpo/V2.1.1/CPOLocationsRouterV211.ts
-import { OCPIServerRoute, ServerAction } from '../../../../../types/Server';
/* eslint-disable @typescript-eslint/no-misused-promises */
+import { OCPIServerRoute, ServerAction } from '../../../../../types/Server';
import express, { NextFunction, Request, Response } from 'express';
import CPOLocationsService from '../../../service/cpo/v2.1.1/CPOLocationsService';
import RouterUtils from '../../../../../utils/RouterUtils';
-export default class OCPICPOV211Router {
+export default class CPOLocationsRouterV211 {
private router: express.Router;
public constructor() {

ADD
src/server/ocpi/router/cpo/V2.1.1/CPOTokensRouterV211.ts
+import { OCPIServerRoute, ServerAction } from '../../../../../types/Server';
+/* eslint-disable @typescript-eslint/no-misused-promises */
+import express, { NextFunction, Request, Response } from 'express';
+
+import CPOTokensService from '../../../service/cpo/v2.1.1/CPOTokensService';
+import RouterUtils from '../../../../../utils/RouterUtils';
+
+export default class CPOTokensRouterV211 {
+ private router: express.Router;
+
+ public constructor() {
+ this.router = express.Router();
+ }
+
+ public buildRoutes(): express.Router {
+ this.buildRouteGetTokens();
+ this.buildRoutePutTokens();
+ this.buildRoutePatchTokens();
+ return this.router;
+ }
+
+ protected buildRouteGetTokens(): void {
+ this.router.get(`/${OCPIServerRoute.OCPI_TOKENS}/*`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(CPOTokensService.handleGetToken.bind(this), ServerAction.OCPI_CPO_GET_TOKEN, req, res, next);
+ });
+ }
+
+ protected buildRoutePutTokens(): void {
+ this.router.put(`/${OCPIServerRoute.OCPI_TOKENS}/*`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(CPOTokensService.handlePutToken.bind(this), ServerAction.OCPI_CPO_PUT_TOKEN, req, res, next);
+ });
+ }
+
+ protected buildRoutePatchTokens(): void {
+ this.router.patch(`/${OCPIServerRoute.OCPI_TOKENS}/*`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(CPOTokensService.handlePatchToken.bind(this), ServerAction.OCPI_CPO_PATCH_TOKEN, req, res, next);
+ });
+ }
+}

MODIFY
src/server/ocpi/router/emsp/EMSPRouter.ts
src/server/ocpi/router/emsp/EMSPRouter.ts
import { OCPIServerRoute, ServerAction } from '../../../../types/Server';
import express, { NextFunction, Request, Response } from 'express';
+import EMSPRouterV211 from './V2.1.1/EMSPRouterV211';
import EMSPVersionsService from '../../service/emsp/EMSPVersionsService';
-import OCPIEMSPV211Router from './V2.1.1/OCPIEMSPV211Router';
import RouterUtils from '../../../../utils/RouterUtils';
export default class EMSPRouter {
@@ -26,6 +26,6 @@ export default class EMSPRouter {
}
protected buildRouteEmspV211(): void {
- this.router.use('/2.1.1', new OCPIEMSPV211Router().buildRoutes());
+ this.router.use('/2.1.1', new EMSPRouterV211().buildRoutes());
}
}

RENAME
src/server/ocpi/router/emsp/V2.1.1/OCPIEMSPV211Router.ts
src/server/ocpi/router/emsp/V2.1.1/EMSPRouterV211.ts
/* eslint-disable @typescript-eslint/no-misused-promises */
import express from 'express';
-export default class OCPIEMSPV211Router {
+export default class EMSPRouterV211 {
private router: express.Router;
public constructor() {

RENAME
src/server/ocpi/ocpi-services-impl/ocpi-2.1.1/cpo/CPOTokensEndpoint.ts
src/server/ocpi/service/cpo/v2.1.1/CPOTokensService.ts
import { NextFunction, Request, Response } from 'express';
-import AbstractEndpoint from '../../AbstractEndpoint';
-import AbstractOCPIService from '../../../AbstractOCPIService';
import AppError from '../../../../../exception/AppError';
-import OCPIEndpoint from '../../../../../types/ocpi/OCPIEndpoint';
-import { OCPIResponse } from '../../../../../types/ocpi/OCPIResponse';
import { OCPIStatusCode } from '../../../../../types/ocpi/OCPIStatusCode';
import { OCPIToken } from '../../../../../types/ocpi/OCPIToken';
import OCPIUtils from '../../../OCPIUtils';
-import OCPIUtilsService from '../../../service/OCPIUtilsService';
+import OCPIUtilsService from '../../OCPIUtilsService';
import { ServerAction } from '../../../../../types/Server';
import { StatusCodes } from 'http-status-codes';
import TagStorage from '../../../../../storage/mongodb/TagStorage';
import Tenant from '../../../../../types/Tenant';
-const MODULE_NAME = 'CPOTokensEndpoint';
+const MODULE_NAME = 'CPOTokensService';
-export default class CPOTokensEndpoint extends AbstractEndpoint {
- public constructor(ocpiService: AbstractOCPIService) {
- super(ocpiService, 'tokens');
- }
-
- public async process(req: Request, res: Response, next: NextFunction, tenant: Tenant, ocpiEndpoint: OCPIEndpoint): Promise<OCPIResponse> {
- switch (req.method) {
- case 'PUT':
- return this.putTokenRequest(req, res, next, tenant, ocpiEndpoint);
- case 'PATCH':
- return this.patchTokenRequest(req, res, next, tenant);
- case 'GET':
- return this.getTokenRequest(req, res, next, tenant);
- }
- }
-
- private async getTokenRequest(req: Request, res: Response, next: NextFunction, tenant: Tenant): Promise<OCPIResponse> {
+export default class CPOTokensService {
+ public static async handleGetToken(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ const { tenant } = req;
const urlSegment = req.path.substring(1).split('/');
// Remove action
urlSegment.shift();
@@ -42,37 +24,28 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const tokenId = urlSegment.shift();
if (!tokenId) {
throw new AppError({
- action: ServerAction.OCPI_CPO_GET_TOKEN,
- module: MODULE_NAME, method: 'getToken',
+ module: MODULE_NAME, method: 'handleGetToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: 'Token ID is not provided',
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
});
}
// Retrieve token
- const token = await this.getToken(tenant, countryCode, partyId, tokenId);
+ const token = await CPOTokensService.getToken(tenant, countryCode, partyId, tokenId);
if (!token) {
throw new AppError({
- action: ServerAction.OCPI_CPO_GET_TOKEN,
- module: MODULE_NAME, method: 'getToken',
+ module: MODULE_NAME, method: 'handleGetToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: `Token ID '${tokenId}' not found`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
});
}
- return OCPIUtils.success(token);
- }
-
- private async getToken(tenant: Tenant, countryId: string, partyId: string, tokenId: string): Promise<OCPIToken> {
- const tag = await TagStorage.getTag(tenant, tokenId, { withUser: true });
- if (tag?.user) {
- if (!tag.user.issuer && tag.user.name === OCPIUtils.buildOperatorName(countryId, partyId) && tag.ocpiToken) {
- return tag.ocpiToken;
- }
- }
+ res.json(OCPIUtils.success(token));
+ next();
}
- private async putTokenRequest(req: Request, res: Response, next: NextFunction, tenant: Tenant, ocpiEndpoint: OCPIEndpoint): Promise<OCPIResponse> {
+ public static async handlePutToken(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ const { tenant } = req;
const urlSegment = req.path.substring(1).split('/');
// Remove action
urlSegment.shift();
@@ -82,8 +55,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const tokenId = urlSegment.shift();
if (!tokenId) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: 'Token ID is not provided',
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
@@ -92,8 +64,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const token = req.body as OCPIToken;
if (!token) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: `Missing content to put Token ID '${tokenId}'`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
@@ -103,8 +74,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const tag = await TagStorage.getTag(tenant, tokenId, { withUser: true });
if (!tag) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: `Token ID '${tokenId}' not found`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -113,8 +83,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
if (tag.issuer) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.NOT_FOUND,
message: `Token ID '${tokenId}' is local to the tenant`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -123,8 +92,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
if (tag.user?.issuer) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.NOT_FOUND,
message: `User found for Token ID '${tokenId}' is local to the tenant`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -134,8 +102,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const operator = OCPIUtils.buildOperatorName(countryCode, partyId);
if (tag.user.name !== operator) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PUT_TOKEN,
- module: MODULE_NAME, method: 'putToken',
+ module: MODULE_NAME, method: 'handlePutToken', action,
errorCode: StatusCodes.CONFLICT,
message: `${operator} is not the owner of the Token ID '${tokenId}'`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -143,10 +110,12 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
});
}
await OCPIUtilsService.updateCpoToken(tenant, token, tag, tag.user, ServerAction.OCPI_CPO_PUT_TOKEN);
- return OCPIUtils.success();
+ res.json(OCPIUtils.success());
+ next();
}
- private async patchTokenRequest(req: Request, res: Response, next: NextFunction, tenant: Tenant): Promise<OCPIResponse> {
+ public static async handlePatchToken(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ const { tenant } = req;
const urlSegment = req.path.substring(1).split('/');
// Remove action
urlSegment.shift();
@@ -157,8 +126,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const token = req.body as OCPIToken;
if (!token) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: `Missing content to patch Token ID '${tokenId}'`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
@@ -168,8 +136,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const tag = await TagStorage.getTag(tenant, tokenId, { withUser: true });
if (!tag?.ocpiToken || tag?.issuer) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.NOT_FOUND,
message: `Token ID '${tokenId}' is local to the tenant`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -178,8 +145,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
if (!tag.user) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.NOT_FOUND,
message: `Token ID '${tokenId}' is not assigned to a user`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -188,8 +154,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
if (tag.user.issuer) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.NOT_FOUND,
message: `Token ID '${tokenId}' is assigned to a user that belongs to the local tenant`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -199,8 +164,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
const operator = OCPIUtils.buildOperatorName(countryCode, partyId);
if (tag.user.name !== operator) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.CONFLICT,
message: `${operator} is not the owner of the Token ID '${tokenId}'`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR,
@@ -235,8 +199,7 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
if (!patched) {
throw new AppError({
- action: ServerAction.OCPI_CPO_PATCH_TOKEN,
- module: MODULE_NAME, method: 'patchToken',
+ module: MODULE_NAME, method: 'handlePatchToken', action,
errorCode: StatusCodes.BAD_REQUEST,
message: `Missing or invalid content to patch Token ID '${tokenId}'`,
ocpiError: OCPIStatusCode.CODE_2001_INVALID_PARAMETER_ERROR
@@ -244,7 +207,16 @@ export default class CPOTokensEndpoint extends AbstractEndpoint {
}
tag.userID = tag.user.id;
await TagStorage.saveTag(tenant, tag);
- return OCPIUtils.success();
- }
+ res.json(OCPIUtils.success());
+ next();
}
+ private static async getToken(tenant: Tenant, countryId: string, partyId: string, tokenId: string): Promise<OCPIToken> {
+ const tag = await TagStorage.getTag(tenant, tokenId, { withUser: true });
+ if (tag?.user) {
+ if (!tag.user.issuer && tag.user.name === OCPIUtils.buildOperatorName(countryId, partyId) && tag.ocpiToken) {
+ return tag.ocpiToken;
+ }
+ }
+ }
+}

MODIFY
src/server/rest/RestServer.ts
src/server/rest/RestServer.ts
@@ -3,8 +3,8 @@ import { Application, NextFunction, Request, Response } from 'express';
import AuthService from './v1/service/AuthService';
import CentralSystemRestServiceConfiguration from '../../types/configuration/CentralSystemRestServiceConfiguration';
import ExpressUtils from '../ExpressUtils';
+import GlobalRouterV1 from './v1/router/GlobalRouterV1';
import Logging from '../../utils/Logging';
-import RestGlobalRouterV1 from './v1/router/RestGlobalRouterV1';
import RestServerService from './RestServerService';
import { ServerType } from '../../types/Server';
import { ServerUtils } from '../ServerUtils';
@@ -27,7 +27,7 @@ export default class RestServer {
// Authentication
this.expressApplication.use(AuthService.initialize());
// Routers
- this.expressApplication.use('/v1', new RestGlobalRouterV1().buildRoutes());
+ this.expressApplication.use('/v1', new GlobalRouterV1().buildRoutes());
// Secured API
this.expressApplication.use('/client/api/:action',
AuthService.authenticate(),

RENAME
src/server/rest/v1/router/RestGlobalRouterV1.ts
src/server/rest/v1/router/GlobalRouterV1.ts
@@ -26,7 +26,7 @@ import UserRouter from './api/UserRouter';
import UtilRouter from './util/UtilRouter';
import express from 'express';
-export default class RestGlobalRouterV1 {
+export default class GlobalRouterV1 {
private router: express.Router;
public constructor() {

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -672,6 +672,7 @@ export enum RESTServerRoute {
export enum OCPIServerRoute {
OCPI_VERSIONS = 'versions',
OCPI_LOCATIONS = 'locations',
+ OCPI_TOKENS = 'tokens',
}
export enum ServerProtocol {

Migrated OCPI CPO Tokens endpoint