Added notifications endpoints + schemas
ADD
src/assets/server/rest/v1/schemas/notification/notifications-end-user-report-error.json
+{
+ "title": "End User Report Error",
+ "description": "",
+ "type": "object",
+ "properties": {
+ "subject": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "description": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "mobile": {
+ "type": "string",
+ "sanitize": "mongo",
+ "pattern": "^\\+?([0-9] ?){9,14}[0-9]$"
+ }
+ },
+ "required": [
+ "subject",
+ "description"
+ ]
+}

ADD
src/assets/server/rest/v1/schemas/notification/notifications-get.json
+{
+ "title": "Get Notifications",
+ "description": "",
+ "type": "object",
+ "properties": {
+ "UserID": {
+ "$ref": "user.json#/definitions/id"
+ },
+ "DateFrom": {
+ "type": "string",
+ "format": "date-time",
+ "sanitize": "mongo"
+ },
+ "Channel": {
+ "type": "string",
+ "sanitize": "mongo",
+ "enum": [
+ "email",
+ "remote-push-notification"
+ ]
+ },
+ "SortFields": {
+ "$ref": "common.json#/definitions/sortFields"
+ },
+ "Limit": {
+ "$ref": "common.json#/definitions/limit"
+ },
+ "Skip": {
+ "$ref": "common.json#/definitions/skip"
+ }
+ },
+ "required": []
+}

MODIFY
src/server/rest/v1/router/GlobalRouter.ts
src/server/rest/v1/router/GlobalRouter.ts
@@ -8,6 +8,7 @@ import CarRouter from './api/CarRouter';
import ChargingStationRouter from './api/ChargingStationRouter';
import ConnectionRouter from './api/ConnectionRouter';
import LoggingRouter from './api/LoggingRouter';
+import NotificationRouter from './api/NotificationRouter';
import { StatusCodes } from 'http-status-codes';
import SwaggerRouter from './doc/SwaggerRouter';
import TagRouter from './api/TagRouter';
@@ -47,6 +48,7 @@ export default class GlobalRouter {
new ChargingStationRouter().buildRoutes(),
new ConnectionRouter().buildRoutes(),
new LoggingRouter().buildRoutes(),
+ new NotificationRouter().buildRoutes(),
new TagRouter().buildRoutes(),
new TenantRouter().buildRoutes(),
new TransactionRouter().buildRoutes(),

ADD
src/server/rest/v1/router/api/NotificationRouter.ts
+/* eslint-disable @typescript-eslint/no-misused-promises */
+import { ServerAction, ServerRoute } from '../../../../../types/Server';
+import express, { NextFunction, Request, Response } from 'express';
+
+import NotificationService from '../../service/NotificationService';
+import RouterUtils from '../RouterUtils';
+
+export default class NotificationRouter {
+ private router: express.Router;
+
+ public constructor() {
+ this.router = express.Router();
+ }
+
+ public buildRoutes(): express.Router {
+ this.buildRouteNotifications();
+ this.buildRouteEndUserReportError();
+ return this.router;
+ }
+
+ protected buildRouteNotifications(): void {
+ this.router.get(`/${ServerRoute.REST_NOTIFICATIONS}`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(NotificationService.handleGetNotifications.bind(this), ServerAction.NOTIFICATIONS, req, res, next);
+ });
+ }
+
+ protected buildRouteEndUserReportError(): void {
+ this.router.post(`/${ServerRoute.REST_NOTIFICATIONS_END_USER_REPORT_ERROR}`, async (req: Request, res: Response, next: NextFunction) => {
+ await RouterUtils.handleServerAction(NotificationService.handleEndUserReportError.bind(this), ServerAction.END_USER_REPORT_ERROR, req, res, next);
+ });
+ }
+}

MODIFY
src/server/rest/v1/service/NotificationService.ts
src/server/rest/v1/service/NotificationService.ts
@@ -7,8 +7,8 @@ import Constants from '../../../../utils/Constants';
import { EndUserErrorNotification } from '../../../../types/UserNotifications';
import { HTTPAuthError } from '../../../../types/HTTPError';
import NotificationHandler from '../../../../notification/NotificationHandler';
-import NotificationSecurity from './security/NotificationSecurity';
import NotificationStorage from '../../../../storage/mongodb/NotificationStorage';
+import NotificationValidator from '../validator/NotificationValidator';
import { ServerAction } from '../../../../types/Server';
import UserStorage from '../../../../storage/mongodb/UserStorage';
import Utils from '../../../../utils/Utils';
@@ -19,7 +19,7 @@ const MODULE_NAME = 'NotificationService';
export default class NotificationService {
static async handleGetNotifications(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Filter
- const filteredRequest = NotificationSecurity.filterNotificationsRequest(req.query);
+ const filteredRequest = NotificationValidator.getInstance().validateGetNotificationsReq(req.query);
// Check User
let userProject: string[] = [];
if ((await Authorizations.canListUsers(req.user)).authorized) {
@@ -60,9 +60,7 @@ export default class NotificationService {
});
}
// Filter
- const filteredRequest = NotificationSecurity.filterEndUserReportErrorRequest(req.body);
- // Check if Notification is valid
- UtilsService.checkIfEndUserErrorNotificationValid(filteredRequest, req);
+ const filteredRequest = NotificationValidator.getInstance().validateEndUserReportErrorReq(req.body);
// Check and Get User
const user = await UtilsService.checkAndGetUserAuthorization(
req.tenant, req.user, req.user.id, Action.READ, action);

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
import { Action, Entity } from '../../../../types/Authorization';
-import { Car, CarCatalog, CarType } from '../../../../types/Car';
+import { Car, CarCatalog } from '../../../../types/Car';
import ChargingStation, { ChargePoint, Voltage } from '../../../../types/ChargingStation';
import { HTTPAuthError, HTTPError } from '../../../../types/HTTPError';
import { NextFunction, Request, Response } from 'express';
+import Tenant, { TenantComponents } from '../../../../types/Tenant';
import User, { UserRole, UserStatus } from '../../../../types/User';
import AppAuthError from '../../../../exception/AppAuthError';
@@ -20,7 +21,6 @@ import Constants from '../../../../utils/Constants';
import Cypher from '../../../../utils/Cypher';
import { DataResult } from '../../../../types/DataResult';
import { EntityDataType } from '../../../../types/GlobalType';
-import { HttpEndUserReportErrorRequest } from '../../../../types/requests/HttpNotificationRequest';
import Logging from '../../../../utils/Logging';
import OCPIEndpoint from '../../../../types/ocpi/OCPIEndpoint';
import OICPEndpoint from '../../../../types/oicp/OICPEndpoint';
@@ -32,8 +32,6 @@ import SiteAreaStorage from '../../../../storage/mongodb/SiteAreaStorage';
import SiteStorage from '../../../../storage/mongodb/SiteStorage';
import Tag from '../../../../types/Tag';
import TagStorage from '../../../../storage/mongodb/TagStorage';
-import Tenant, { TenantComponents } from '../../../../types/Tenant';
-
import { TransactionInErrorType } from '../../../../types/InError';
import UserStorage from '../../../../storage/mongodb/UserStorage';
import UserToken from '../../../../types/UserToken';
@@ -1679,36 +1677,6 @@ export default class UtilsService {
}
}
- public static checkIfEndUserErrorNotificationValid(endUserErrorNotificationValid: HttpEndUserReportErrorRequest, req: Request): void {
- if (!endUserErrorNotificationValid.subject) {
- throw new AppError({
- source: Constants.CENTRAL_SERVER,
- errorCode: HTTPError.GENERAL_ERROR,
- message: 'Subject is mandatory.',
- module: MODULE_NAME, method: 'checkIfEndUserErrorNotificationValid',
- user: req.user.id
- });
- }
- if (!endUserErrorNotificationValid.description) {
- throw new AppError({
- source: Constants.CENTRAL_SERVER,
- errorCode: HTTPError.GENERAL_ERROR,
- message: 'Description is mandatory.',
- module: MODULE_NAME, method: 'checkIfEndUserErrorNotificationValid',
- user: req.user.id
- });
- }
- if (endUserErrorNotificationValid.mobile && !Utils.isPhoneValid(endUserErrorNotificationValid.mobile)) {
- throw new AppError({
- source: Constants.CENTRAL_SERVER,
- errorCode: HTTPError.GENERAL_ERROR,
- message: 'Phone is invalid',
- module: MODULE_NAME, method: 'checkIfEndUserErrorNotificationValid',
- user: req.user.id
- });
- }
- }
-
// eslint-disable-next-line @typescript-eslint/ban-types
public static async processSensitiveData(tenant: Tenant, currentProperties: object, newProperties: object): Promise<void> {
// Process the sensitive data (if any)

ADD
src/server/rest/v1/validator/NotificationValidator.ts
+import { HttpEndUserReportErrorRequest, HttpNotificationRequest } from '../../../../types/requests/HttpNotificationRequest';
+
+import Schema from '../../../../types/validator/Schema';
+import SchemaValidator from './SchemaValidator';
+import fs from 'fs';
+import global from '../../../../types/GlobalType';
+
+export default class NotificationValidator extends SchemaValidator {
+ private static instance: NotificationValidator|null = null;
+ private notificationsGet: Schema;
+ private notificationsEndUserReportError: Schema;
+
+ private constructor() {
+ super('NotificationValidator');
+ this.notificationsGet = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/notification/notifications-get.json`, 'utf8'));
+ this.notificationsEndUserReportError = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/notification/notifications-end-user-report-error.json`, 'utf8'));
+ }
+
+ public static getInstance(): NotificationValidator {
+ if (!NotificationValidator.instance) {
+ NotificationValidator.instance = new NotificationValidator();
+ }
+ return NotificationValidator.instance;
+ }
+
+ public validateGetNotificationsReq(data: any): HttpNotificationRequest {
+ // Validate schema
+ this.validate(this.notificationsGet, data);
+ return data;
+ }
+
+ public validateEndUserReportErrorReq(data: any): HttpEndUserReportErrorRequest {
+ // Validate schema
+ this.validate(this.notificationsEndUserReportError, data);
+ return data;
+ }
+}

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -554,6 +554,9 @@ export enum ServerRoute {
REST_LOGGING = 'loggings/:id',
REST_LOGGINGS_EXPORT = 'loggings/action/export',
+ REST_NOTIFICATIONS = 'notifications',
+ REST_NOTIFICATIONS_END_USER_REPORT_ERROR = 'notifications/action/end-user/report-error',
+
// BILLING URLs for CRUD operations on PAYMENT METHODS
REST_BILLING_PAYMENT_METHODS = 'users/:userID/payment-methods',
REST_BILLING_PAYMENT_METHOD = 'users/:userID/payment-methods/:paymentMethodID',

Added notifications endpoints + schemas