Removed handleAddUsersCar() as same as handleUpdateUsersCar() + move out logic of handling userscar savin from Storage to Service + Align Car types between front-end and backend
MODIFY
src/migration/tasks/UpdateChargingStationTemplatesTask.ts
src/migration/tasks/UpdateChargingStationTemplatesTask.ts
import OCPPUtils from '../../server/ocpp/utils/OCPPUtils';
import ChargingStationStorage from '../../storage/mongodb/ChargingStationStorage';
+import TenantStorage from '../../storage/mongodb/TenantStorage';
+import { OCPPChangeConfigurationCommandResult, OCPPConfigurationStatus } from '../../types/ocpp/OCPPClient';
+import { ServerAction } from '../../types/Server';
+import Tenant from '../../types/Tenant';
import Constants from '../../utils/Constants';
import Logging from '../../utils/Logging';
+import Utils from '../../utils/Utils';
import MigrationTask from '../MigrationTask';
import { ActionsResponse } from './../../types/GlobalType';

MODIFY
src/server/rest/CentralRestServerService.ts
src/server/rest/CentralRestServerService.ts
@@ -97,7 +97,7 @@ class RequestMapper {
[ServerAction.INTEGRATION_CONNECTION_CREATE]: ConnectionService.handleCreateConnection.bind(this),
[ServerAction.CHARGING_STATION_REQUEST_OCPP_PARAMETERS]: ChargingStationService.handleRequestChargingStationOcppParameters.bind(this),
[ServerAction.CAR_CREATE]: CarService.handleCarCreate.bind(this),
- [ServerAction.ADD_USERS_TO_CAR]: CarService.handleAddUsersToCar.bind(this)
+ [ServerAction.ADD_USERS_TO_CAR]: CarService.handleUpdateUsersCar.bind(this)
});
break;
@@ -211,7 +211,7 @@ class RequestMapper {
[ServerAction.OCPI_ENDPOINT_UNREGISTER]: OCPIEndpointService.handleUnregisterOcpiEndpoint.bind(this),
[ServerAction.SYNCHRONIZE_CAR_CATALOGS]: CarService.handleSynchronizeCarCatalogs.bind(this),
[ServerAction.CAR_UPDATE]: CarService.handleUpdateCar.bind(this),
- [ServerAction.USERS_CAR_UPDATE]: CarService.handleUpdateUsersCar.bind(this),
+ [ServerAction.UPDATE_USERS_CAR]: CarService.handleUpdateUsersCar.bind(this),
});
break;

MODIFY
src/server/rest/service/CarService.ts
src/server/rest/service/CarService.ts
@@ -18,6 +18,7 @@ import User from '../../../types/User';
import Utils from '../../../utils/Utils';
import UtilsService from './UtilsService';
import UserStorage from '../../../storage/mongodb/UserStorage';
+import { ActionsResponse } from '../../../types/GlobalType';
const MODULE_NAME = 'CarService';
@@ -270,7 +271,7 @@ export default class CarService {
if (Authorizations.isBasic(req.user)) {
// Clear default car
if (filteredRequest.isDefault) {
- await CarStorage.clearDefaultUserCar(req.user.tenantID, req.user.id);
+ await CarStorage.clearUserCarDefault(req.user.tenantID, req.user.id);
}
// Assign to User
const newUserCar: UserCar = {
@@ -372,7 +373,7 @@ export default class CarService {
// Only one property in userscars: Default
if (userCar.default !== filteredRequest.isDefault) {
if (filteredRequest.isDefault) {
- await CarStorage.clearDefaultUserCar(req.user.tenantID, req.user.id);
+ await CarStorage.clearUserCarDefault(req.user.tenantID, req.user.id);
}
userCar.default = filteredRequest.isDefault;
userCar.lastChangedBy = { 'id': req.user.id };
@@ -480,72 +481,103 @@ export default class CarService {
next();
}
- public static async handleAddUsersToCar(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ public static async handleUpdateUsersCar(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Check if component is active
- UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.CAR, Action.CREATE, Entity.USERS_CARS,
- MODULE_NAME, 'handleAddUsersToCar');
- // Check auth
+ UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.CAR, Action.UPDATE, Entity.USERS_CARS,
+ MODULE_NAME, 'handleUpdateUsersCar');
+ // Update
+ if (action === ServerAction.UPDATE_USERS_CAR) {
+ if (!Authorizations.canAssignUsersCar(req.user)) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.ERROR,
+ user: req.user,
+ action: Action.UPDATE, entity: Entity.USERS_CARS,
+ module: MODULE_NAME, method: 'handleUpdateUsersCar'
+ });
+ }
+ // Add
+ } else if (action === ServerAction.ADD_USERS_TO_CAR) {
if (!Authorizations.canAssignUsersCar(req.user)) {
throw new AppAuthError({
errorCode: HTTPAuthError.ERROR,
user: req.user,
action: Action.CREATE, entity: Entity.USERS_CARS,
- module: MODULE_NAME, method: 'handleAddUsersToCar'
+ module: MODULE_NAME, method: 'handleUpdateUsersCar'
});
}
+ }
const filteredRequest = CarSecurity.filterUsersAssignRequest(req.body);
// CarID is mandatory
- UtilsService.assertIdIsProvided(action, filteredRequest.carID, 'CarSecurity', 'filterUsersAssignRequest', req.user);
+ UtilsService.assertIdIsProvided(action, filteredRequest.carID, MODULE_NAME, 'handleUpdateUsersCar', req.user);
// Check Users
for (const userCar of filteredRequest.usersCar) {
// Check the user
const user = await UserStorage.getUser(req.user.tenantID, userCar.userID);
UtilsService.assertObjectExists(action, user, `User '${userCar.userID}' does not exist`,
- MODULE_NAME, 'handleAssignUsersToSite', req.user);
+ MODULE_NAME, 'handleUpdateUsersCar', req.user);
// Auth
if (!Authorizations.canReadUser(req.user, userCar.userID)) {
throw new AppAuthError({
errorCode: HTTPAuthError.ERROR,
user: req.user,
action: Action.READ, entity: Entity.USER,
- module: MODULE_NAME, method: 'handleAssignUsersToSite',
+ module: MODULE_NAME, method: 'handleUpdateUsersCar',
value: userCar.userID
});
}
}
- const result = await CarStorage.addUsersToCar(req.user.tenantID, filteredRequest.carID, filteredRequest.usersCar);
- // Log
- Utils.logActionsResponse(req.user.tenantID, ServerAction.ADD_USERS_TO_CAR,
- MODULE_NAME, 'AssignUsersCar', result,
- '{{inSuccess}} user(s) were successfully assigned',
- '{{inError}} user(s) failed to be assigned',
- '{{inSuccess}} user(s) were successfully assigned and {{inError}} failed to be assigned',
- 'All the users are up to date'
- );
- // Return
- res.json({ ...result, ...Constants.REST_RESPONSE_SUCCESS });
- next();
+ // Save
+ const actionsDone: ActionsResponse = {
+ inSuccess: 0,
+ inError: 0
+ };
+ for (const userCar of filteredRequest.usersCar) {
+ try {
+ // Check Default
+ if (userCar.default) {
+ await CarStorage.clearUserCarDefault(req.user.tenantID, userCar.userID);
+ }
+ // Check Owner
+ if (userCar.owner) {
+ await CarStorage.clearUserCarOwner(req.user.tenantID, filteredRequest.carID);
+ }
+ // Get from DB
+ const userCarDB = await CarStorage.getUserCarByCarUser(req.user.tenantID, filteredRequest.carID, userCar.userID);
+ // Update
+ if (userCarDB) {
+ userCarDB.owner = userCar.owner;
+ userCarDB.default = userCar.default;
+ // Save
+ await CarStorage.saveUserCar(req.user.tenantID, userCarDB);
+ // Create
+ } else {
+ userCar.carID = filteredRequest.carID;
+ userCar.lastChangedOn = new Date();
+ await CarStorage.saveUserCar(req.user.tenantID, userCar);
}
-
- public static async handleUpdateUsersCar(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- // Check if component is active
- UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.CAR, Action.UPDATE, Entity.USERS_CARS,
- MODULE_NAME, 'handleUpdateUsersCar');
- // Check auth
- if (!Authorizations.canAssignUsersCar(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.ERROR,
- user: req.user,
- action: Action.UPDATE, entity: Entity.USERS_CARS,
- module: MODULE_NAME, method: 'handleUpdateUsersCar'
+ actionsDone.inSuccess++;
+ } catch (error) {
+ Logging.logError({
+ tenantID: req.user.tenantID,
+ user: userCar.userID,
+ source: Constants.CENTRAL_SERVER,
+ module: MODULE_NAME, method: 'handleUpdateUsersCar',
+ action: ServerAction.UPDATE_USERS_CAR,
+ message: 'An error occurred while trying to assign the user to the car',
+ detailedMessages: { error: error.message, stack: error.stack, userCar }
});
+ actionsDone.inError++;
}
- const filteredRequest = CarSecurity.filterUsersAssignRequest(req.body);
- // CarID is mandatory
- UtilsService.assertIdIsProvided(action, filteredRequest.carID, 'CarSecurity', 'filterUsersAssignRequest', req.user);
- const result = await CarStorage.updateUsersCar(req.user.tenantID, filteredRequest.carID, filteredRequest.usersCar);
-
- res.json({ ...result, ...Constants.REST_RESPONSE_SUCCESS });
+ }
+ // Log
+ Utils.logActionsResponse(req.user.tenantID, ServerAction.UPDATE_USERS_CAR,
+ MODULE_NAME, 'handleUpdateUsersCar', actionsDone,
+ '{{inSuccess}} user(s) were successfully updated',
+ '{{inError}} user(s) failed to be updated',
+ '{{inSuccess}} user(s) were successfully updated and {{inError}} failed to be updated',
+ 'All the users are up to date'
+ );
+ res.json({ ...actionsDone, ...Constants.REST_RESPONSE_SUCCESS });
next();
}
@@ -559,13 +591,49 @@ export default class CarService {
errorCode: HTTPAuthError.ERROR,
user: req.user,
action: Action.DELETE, entity: Entity.USERS_CARS,
- module: MODULE_NAME, method: 'handleDeleteUsersCar'
+ module: MODULE_NAME, method: 'handleRemoveUsersFromCar'
});
}
const usersCarIDs = CarSecurity.filterUsersCarRequestByIDs(req.body);
- const result = await CarStorage.removeUsersFromCar(req.user.tenantID, usersCarIDs);
-
- res.json({ ...result, ...Constants.REST_RESPONSE_SUCCESS });
+ // Check Users
+ for (const userCarID of usersCarIDs) {
+ // Check the user
+ const userCar = await CarStorage.getUserCar(req.user.tenantID, userCarID);
+ UtilsService.assertObjectExists(action, userCar, `User Car ID '${userCarID}' does not exist`,
+ MODULE_NAME, 'handleRemoveUsersFromCar', req.user);
+ // Auth
+ if (!Authorizations.canReadUser(req.user, userCar.userID)) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.ERROR,
+ user: req.user,
+ action: Action.READ, entity: Entity.USER,
+ module: MODULE_NAME, method: 'handleRemoveUsersFromCar',
+ value: userCar.userID
+ });
+ }
+ }
+ // Delete
+ const actionsDone: ActionsResponse = {
+ inSuccess: 0,
+ inError: 0
+ };
+ for (const userCarID of usersCarIDs) {
+ try {
+ await CarStorage.deleteUserCar(req.user.tenantID, userCarID);
+ actionsDone.inSuccess++;
+ } catch (error) {
+ actionsDone.inError++;
+ }
+ }
+ // Log
+ Utils.logActionsResponse(req.user.tenantID, ServerAction.REMOVE_USERS_FROM_CAR,
+ MODULE_NAME, 'handleRemoveUsersFromCar', actionsDone,
+ '{{inSuccess}} user(s) were successfully deleted',
+ '{{inError}} user(s) failed to be deleted',
+ '{{inSuccess}} user(s) were successfully deleted and {{inError}} failed to be deleted',
+ 'All the users are up to date'
+ );
+ res.json({ ...actionsDone, ...Constants.REST_RESPONSE_SUCCESS });
next();
}

MODIFY
src/storage/mongodb/CarStorage.ts
src/storage/mongodb/CarStorage.ts
@@ -510,125 +510,6 @@ export default class CarStorage {
return userCarMDB._id.toHexString();
}
- public static async addUsersToCar(tenantID: string, carID: string, usersCarToSave: UserCar[]): Promise<ActionsResponse> {
- // Debug
- const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'addUsersToCar');
- const actionsDone: ActionsResponse = {
- inSuccess: 0,
- inError: 0
- };
- // Check Tenant
- await Utils.checkTenant(tenantID);
- // Set
- for (const userCar of usersCarToSave) {
- try {
- if (userCar.default) {
- await CarStorage.clearDefaultUserCar(tenantID, userCar.userID);
- }
- userCar.carID = carID;
- userCar.createdOn = new Date();
- await CarStorage.saveUserCar(tenantID, userCar);
- actionsDone.inSuccess++;
- } catch (error) {
- Logging.logError({
- tenantID,
- user: userCar.userID,
- source: Constants.CENTRAL_SERVER,
- module: MODULE_NAME, method: 'addUsersToCar',
- action: ServerAction.USERS_CAR_UPDATE,
- message: 'An error occurred while trying to assign the user to the car',
- detailedMessages: { error: error.message, stack: error.stack, userCar }
- });
- actionsDone.inError++;
- }
- }
- // Debug
- Logging.traceEnd(MODULE_NAME, 'addUsersToCar', uniqueTimerID, { usersCarToSave });
- return actionsDone;
- }
-
- public static async removeUsersFromCar(tenantID: string, usersCarIDs: string[]): Promise<ActionsResponse> {
- // Debug
- const actionsDone: ActionsResponse = {
- inSuccess: 0,
- inError: 0
- };
- await Utils.checkTenant(tenantID);
- // Set
- for (const userCarID of usersCarIDs) {
- try {
- await global.database.getCollection(tenantID, 'userscars')
- .findOneAndDelete({ '_id': Utils.convertToObjectID(userCarID) });
- actionsDone.inSuccess++;
- } catch (error) {
- actionsDone.inError++;
- }
- }
- // Log
- Utils.logActionsResponse(tenantID, ServerAction.REMOVE_USERS_FROM_CAR,
- MODULE_NAME, 'removeUsersFromCar', actionsDone,
- '{{inSuccess}} user(s) were successfully deleted',
- '{{inError}} user(s) failed to be deleted',
- '{{inSuccess}} user(s) were successfully deleted and {{inError}} failed to be deleted',
- 'All the users are up to date'
- );
- return actionsDone;
- }
-
-
- public static async updateUsersCar(tenantID: string, carID: string, usersCarToSave: UserCar[]): Promise<ActionsResponse> {
- // Debug
- const actionsDone: ActionsResponse = {
- inSuccess: 0,
- inError: 0
- };
- await Utils.checkTenant(tenantID);
- // Set
- for (const userCar of usersCarToSave) {
- try {
- const userCarDB = await CarStorage.getUserCarByCarUser(tenantID, carID, userCar.userID);
- if (userCarDB) {
- if (userCarDB.default !== userCar.default || !userCarDB.active || (userCar.owner && !userCarDB.owner)) {
- if (userCar.default) {
- await CarStorage.clearDefaultUserCar(tenantID, userCar.userID);
- }
- if (userCar.owner && !userCarDB.owner) {
- await CarStorage.clearUserCarOwner(tenantID, carID);
- }
- userCarDB.owner = userCar.owner;
- userCarDB.active = true;
- userCarDB.default = userCar.default;
- await CarStorage.saveUserCar(tenantID, userCarDB);
- actionsDone.inSuccess++;
- }
- } else {
- if (userCar.default) {
- await CarStorage.clearDefaultUserCar(tenantID, userCar.userID);
- }
- if (userCar.owner) {
- await CarStorage.clearUserCarOwner(tenantID, carID);
- }
- userCar.carID = carID;
- userCar.lastChangedOn = new Date();
- userCar.active = true;
- await CarStorage.saveUserCar(tenantID, userCar);
- actionsDone.inSuccess++;
- }
- } catch (error) {
- actionsDone.inError++;
- }
- }
- // Log
- Utils.logActionsResponse(tenantID, ServerAction.USERS_CAR_UPDATE,
- MODULE_NAME, 'updateUsersCar', actionsDone,
- '{{inSuccess}} user(s) were successfully updated',
- '{{inError}} user(s) failed to be updated',
- '{{inSuccess}} user(s) were successfully updated and {{inError}} failed to be updated',
- 'All the users are up to date'
- );
- return actionsDone;
- }
-
public static async getCar(tenantID: string, carID: string = Constants.UNKNOWN_STRING_ID,
params?: { withUsers?: boolean }, projectFields?: string[]): Promise<Car> {
// Debug
@@ -775,7 +656,7 @@ export default class CarStorage {
};
}
- public static async clearDefaultUserCar(tenantID: string, userID: string): Promise<void> {
+ public static async clearUserCarDefault(tenantID: string, userID: string): Promise<void> {
const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'clearDefaultCar');
await Utils.checkTenant(tenantID);
await global.database.getCollection<any>(tenantID, 'userscars').updateMany(
@@ -817,8 +698,30 @@ export default class CarStorage {
return usersCarsMDB.count > 0 ? usersCarsMDB.result[0] : null;
}
+ public static async getUserCar(tenantID: string, userCarID: string = Constants.UNKNOWN_STRING_ID,
+ projectFields?: string[]): Promise<UserCar> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'getUserCar');
+ // Query single Car
+ const usersCarsMDB = await CarStorage.getUsersCars(tenantID,
+ { usersCarsIDs: [userCarID] },
+ Constants.DB_PARAMS_SINGLE_RECORD, projectFields);
+ Logging.traceEnd(MODULE_NAME, 'getUserCar', uniqueTimerID, { userCarID });
+ return usersCarsMDB.count > 0 ? usersCarsMDB.result[0] : null;
+ }
+
+ public static async deleteUserCar(tenantID: string, id: string): Promise<void> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'deleteUserCar');
+ // Delete singular site area
+ await global.database.getCollection(tenantID, 'userscars')
+ .findOneAndDelete({ '_id': Utils.convertToObjectID(id) });
+ // Debug
+ Logging.traceEnd(MODULE_NAME, 'deleteUserCar', uniqueTimerID, { id });
+ }
+
public static async getUsersCars(tenantID: string,
- params: { search?: string; userscarsIDs?: string[]; userIDs?: string[]; carIDs?: string[]; active?: boolean } = {},
+ params: { search?: string; usersCarsIDs?: string[]; userIDs?: string[]; carIDs?: string[]; active?: boolean } = {},
dbParams?: DbParams, projectFields?: string[]): Promise<DataResult<UserCar>> {
// Debug
const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'getUsersCars');
@@ -832,9 +735,9 @@ export default class CarStorage {
filters.active = params.active;
}
// Limit on Car for Basic Users
- if (!Utils.isEmptyArray(params.userscarsIDs)) {
+ if (!Utils.isEmptyArray(params.usersCarsIDs)) {
// Build filter
- filters._id = { $in: params.userscarsIDs.map((userscarsID) => Utils.convertToObjectID(userscarsID)) };
+ filters._id = { $in: params.usersCarsIDs.map((userscarsID) => Utils.convertToObjectID(userscarsID)) };
}
if (!Utils.isEmptyArray(params.carIDs)) {
// Build filter

MODIFY
src/types/Car.ts
src/types/Car.ts
@@ -150,7 +150,6 @@ export interface UserCar extends CreatedUpdatedProps {
user?: User;
car?: Car;
default?: boolean;
- active?: boolean;
owner?: boolean;
}

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -62,7 +62,7 @@ export enum ServerAction {
CAR_MAKERS = 'CarMakers',
CAR_CREATE = 'CarCreate',
CAR_UPDATE = 'CarUpdate',
- USERS_CAR_UPDATE = 'UsersCarUpdate',
+ UPDATE_USERS_CAR = 'UsersCarUpdate',
CARS = 'Cars',
CAR = 'Car',
USERS_CAR = 'UsersCar',

Removed handleAddUsersCar() as same as handleUpdateUsersCar() + move out logic of handling userscar savin from Storage to Service + Align Car types between front-end and backend