Added Assets validation schemas
ADD
src/assets/server/rest/v1/schemas/asset/asset-get-consumptions.json
+{
+ "title": "Get Asset Consumptions by ID Request",
+ "type": "object",
+ "properties": {
+ "ID": {
+ "$ref": "asset.json#/definitions/id"
+ },
+ "StartDate": {
+ "type": "string",
+ "format": "date-time",
+ "sanitize": "mongo"
+ },
+ "EndDate": {
+ "type": "string",
+ "format": "date-time",
+ "sanitize": "mongo"
+ }
+ },
+ "required": [
+ "ID",
+ "StartDate",
+ "EndDate"
+ ]
+}

ADD
src/assets/server/rest/v1/schemas/asset/asset-get.json
+{
+ "title": "Get Asset by ID Request",
+ "type": "object",
+ "properties": {
+ "ID": {
+ "$ref": "asset.json#/definitions/id"
+ },
+ "WithSiteArea": {
+ "type": "boolean",
+ "sanitize": "mongo"
+ }
+ },
+ "required": [
+ "ID"
+ ]
+}

ADD
src/assets/server/rest/v1/schemas/asset/asset.json
+{
+ "$id": "asset.json",
+ "definitions": {
+ "id": {
+ "$ref": "common.json#/definitions/id"
+ },
+ "name": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "siteAreaID": {
+ "$ref": "common.json#/definitions/id"
+ },
+ "assetType": {
+ "type": "string",
+ "sanitize": "mongo",
+ "enum": ["CO", "PR", "CO-PR"]
+ },
+ "excludeFromSmartCharging": {
+ "type": "boolean",
+ "sanitize": "mongo"
+ },
+ "variationThresholdPercent": {
+ "type": "number",
+ "sanitize": "mongo"
+ },
+ "fluctuationPercent": {
+ "type": "number",
+ "sanitize": "mongo",
+ "minimum": 0,
+ "maximum": 100
+ },
+ "staticValueWatt": {
+ "type": "number",
+ "sanitize": "mongo"
+ },
+ "image": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "dynamicAsset": {
+ "type": "boolean",
+ "sanitize": "mongo"
+ },
+ "usePushAPI": {
+ "type": "boolean",
+ "sanitize": "mongo"
+ },
+ "coordinates": {
+ "type": "array",
+ "items": {
+ "type": "number",
+ "sanitize": "mongo"
+ }
+ },
+ "connectionID": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "meterID": {
+ "type": "string",
+ "sanitize": "mongo"
+ }
+ }
+}

MODIFY
src/server/rest/v1/service/AssetService.ts
src/server/rest/v1/service/AssetService.ts
@@ -35,7 +35,7 @@ export default class AssetService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
Action.LIST, Entity.ASSETS, MODULE_NAME, 'handleGetAssetConsumption');
// Filter
- const filteredRequest = AssetSecurity.filterAssetConsumptionRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetGetConsumptionsReq(req.query);
UtilsService.assertIdIsProvided(action, filteredRequest.AssetID, MODULE_NAME,
'handleGetAssetConsumption', req.user);
// Check auth
@@ -197,9 +197,9 @@ export default class AssetService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
Action.CHECK_CONNECTION, Entity.ASSET, MODULE_NAME, 'handleCheckAssetConnection');
// Filter request
- const filteredRequest = AssetSecurity.filterAssetRequestByID(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
// Get asset connection type
- const assetImpl = await AssetFactory.getAssetImpl(req.tenant, filteredRequest);
+ const assetImpl = await AssetFactory.getAssetImpl(req.tenant, filteredRequest.ID);
// Asset has unknown connection type
if (!assetImpl) {
throw new AppError({
@@ -255,7 +255,7 @@ export default class AssetService {
});
}
// Filter request
- const assetID = AssetSecurity.filterAssetRequestByID(req.query);
+ const assetID = AssetValidator.getInstance().validateAssetGetReq(req.query).ID;
UtilsService.assertIdIsProvided(action, assetID, MODULE_NAME, 'handleRetrieveConsumption', req.user);
// Get
const asset = await AssetStorage.getAsset(req.tenant, assetID);
@@ -342,7 +342,7 @@ export default class AssetService {
});
}
// Filter
- const filteredRequest = AssetSecurity.filterAssetsRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetsGetReq(req.query);
// Build error type
const errorType = (filteredRequest.ErrorType ? filteredRequest.ErrorType.split('|') : [AssetInErrorType.MISSING_SITE_AREA]);
// Get the assets
@@ -370,7 +370,7 @@ export default class AssetService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
Action.DELETE, Entity.ASSET, MODULE_NAME, 'handleDeleteAsset');
// Filter
- const filteredRequest = AssetSecurity.filterAssetRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
// Check Mandatory fields
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleDeleteAsset', req.user);
// Check auth
@@ -420,7 +420,7 @@ export default class AssetService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
Action.READ, Entity.ASSET, MODULE_NAME, 'handleGetAsset');
// Filter
- const filteredRequest = AssetSecurity.filterAssetRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
// ID is mandatory
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetAsset', req.user);
// Check auth
@@ -444,7 +444,7 @@ export default class AssetService {
public static async handleGetAssetImage(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Filter
- const filteredRequest = AssetSecurity.filterAssetImageRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetGetReq(req.query);
UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetAssetImage', req.user);
// Get it
const assetImage = await AssetStorage.getAssetImage(req.tenant, filteredRequest.ID);
@@ -480,7 +480,7 @@ export default class AssetService {
});
}
// Filter
- const filteredRequest = AssetSecurity.filterAssetsRequest(req.query);
+ const filteredRequest = AssetValidator.getInstance().validateAssetsGetReq(req.query);
// Get authorization filters
const authorizationAssetsFilters = await AuthorizationService.checkAndGetAssetsAuthorizations(
req.tenant, req.user, filteredRequest);
@@ -500,7 +500,12 @@ export default class AssetService {
dynamicOnly: filteredRequest.DynamicOnly,
...authorizationAssetsFilters.filters
},
- { limit: filteredRequest.Limit, skip: filteredRequest.Skip, sort: filteredRequest.SortFields, onlyRecordCount: filteredRequest.OnlyRecordCount },
+ {
+ limit: filteredRequest.Limit,
+ skip: filteredRequest.Skip,
+ sort: UtilsService.httpSortFieldsToMongoDB(filteredRequest.SortFields),
+ onlyRecordCount: filteredRequest.OnlyRecordCount
+ },
authorizationAssetsFilters.projectFields
);
res.json(assets);
@@ -521,7 +526,7 @@ export default class AssetService {
});
}
// Filter
- const filteredRequest = AssetSecurity.filterAssetCreateRequest(req.body);
+ const filteredRequest = AssetValidator.getInstance().validateAssetCreateReq(req.body);
// Check Asset
UtilsService.checkIfAssetValid(filteredRequest, req);
// Check Site Area
@@ -571,7 +576,7 @@ export default class AssetService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.ASSET,
Action.UPDATE, Entity.ASSET, MODULE_NAME, 'handleUpdateAsset');
// Filter
- const filteredRequest = AssetSecurity.filterAssetUpdateRequest(req.body);
+ const filteredRequest = AssetValidator.getInstance().validateAssetUpdateReq(req.body);
// Check auth
if (!await Authorizations.canUpdateAsset(req.user)) {
throw new AppAuthError({

MODIFY
src/server/rest/v1/validator/AssetValidator.ts
src/server/rest/v1/validator/AssetValidator.ts
+import { HttpAssetConsumptionRequest, HttpAssetRequest, HttpAssetsRequest } from '../../../../types/requests/HttpAssetRequest';
+
+import Asset from '../../../../types/Asset';
import Consumption from '../../../../types/Consumption';
import Schema from '../../../../types/validator/Schema';
import SchemaValidator from './SchemaValidator';
@@ -7,10 +10,20 @@ import global from '../../../../types/GlobalType';
export default class AssetValidator extends SchemaValidator {
private static instance: AssetValidator|null = null;
private createAssetConsumption: Schema;
+ private assetGet: Schema;
+ private assetsGet: Schema;
+ private assetCreate: Schema;
+ private assetUpdate: Schema;
+ private assetGetConsumptions: Schema;
private constructor() {
super('AssetValidator');
this.createAssetConsumption = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/create-asset-consumption.json`, 'utf8'));
+ this.assetGet = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/asset-get.json`, 'utf8'));
+ this.assetsGet = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/assets-get.json`, 'utf8'));
+ this.assetCreate = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/asset-create.json`, 'utf8'));
+ this.assetUpdate = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/asset-update.json`, 'utf8'));
+ this.assetGetConsumptions = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/asset-get-consumptions.json`, 'utf8'));
}
public static getInstance(): AssetValidator {
@@ -20,10 +33,39 @@ export default class AssetValidator extends SchemaValidator {
return AssetValidator.instance;
}
- // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
public validateCreateAssetConsumption(data: any): Consumption {
// Validate schema
this.validate(this.createAssetConsumption, data);
return data;
}
+
+ public validateAssetGetReq(data: any): HttpAssetRequest {
+ // Validate schema
+ this.validate(this.assetGet, data);
+ return data;
+ }
+
+ public validateAssetsGetReq(data: any): HttpAssetsRequest {
+ // Validate schema
+ this.validate(this.assetsGet, data);
+ return data;
+ }
+
+ public validateAssetCreateReq(data: Partial<Asset>): Partial<Asset> {
+ // Validate schema
+ this.validate(this.assetCreate, data);
+ return data;
+ }
+
+ public validateAssetUpdateReq(data: Partial<Asset>): Partial<Asset> {
+ // Validate schema
+ this.validate(this.assetUpdate, data);
+ return data;
+ }
+
+ public validateAssetGetConsumptionsReq(data: any): HttpAssetConsumptionRequest {
+ // Validate schema
+ this.validate(this.assetGetConsumptions, data);
+ return data;
+ }
}

MODIFY
src/server/rest/v1/validator/SchemaValidator.ts
src/server/rest/v1/validator/SchemaValidator.ts
@@ -21,6 +21,7 @@ export default class SchemaValidator {
private tagSchema: Schema = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/tag/tag.json`, 'utf8'));
private transactionSchema: Schema = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/transaction/transaction.json`, 'utf8'));
private userSchema: Schema = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/user/user.json`, 'utf8'));
+ private assetSchema: Schema = JSON.parse(fs.readFileSync(`${global.appRoot}/assets/server/rest/v1/schemas/asset/asset.json`, 'utf8'));
constructor(readonly moduleName: string,
config: {
@@ -48,6 +49,7 @@ export default class SchemaValidator {
this.ajv.addSchema(this.tagSchema);
this.ajv.addSchema(this.transactionSchema);
this.ajv.addSchema(this.userSchema);
+ this.ajv.addSchema(this.assetSchema);
}
public validate(schema: Schema, content: any): void {

Added Assets validation schemas