Trigger manually the job that will import the tags/users after upload. Aligned server actions. Optimized/added meaningful logs to track the current import progress
MODIFY
src/scheduler/tasks/ImportTagsTask.ts
src/scheduler/tasks/ImportTagsTask.ts
+import { ActionsResponse, ImportStatus } from '../../types/GlobalType';
import Tag, { ImportedTag } from '../../types/Tag';
import Constants from '../../utils/Constants';
import { DataResult } from '../../types/DataResult';
import DbParams from '../../types/database/DbParams';
-import { ImportStatus } from '../../types/GlobalType';
import LockingHelper from '../../locking/LockingHelper';
import LockingManager from '../../locking/LockingManager';
import Logging from '../../utils/Logging';
@@ -17,12 +17,18 @@ import Utils from '../../utils/Utils';
const MODULE_NAME = 'SynchronizeUsersImportTask';
export default class ImportTagsTask extends SchedulerTask {
- async processTenant(tenant: Tenant, config: TaskConfig): Promise<void> {
+ public async processTenant(tenant: Tenant, config?: TaskConfig): Promise<void> {
const importTagsLock = await LockingHelper.createImportTagsLock(tenant.id);
if (importTagsLock) {
try {
const dbParams: DbParams = { limit: Constants.IMPORT_PAGE_SIZE, skip: 0 };
let importedTags: DataResult<ImportedTag>;
+ const result: ActionsResponse = {
+ inError: 0,
+ inSuccess: 0,
+ };
+ // Get total number of Tags to import
+ const totalTagsToImport = await TagStorage.getImportedTagsCount(tenant.id);
do {
// Get the imported tags
importedTags = await TagStorage.getImportedTags(tenant.id, { status: ImportStatus.READY }, dbParams);
@@ -35,13 +41,7 @@ export default class ImportTagsTask extends SchedulerTask {
await TagStorage.saveTag(tenant.id, { ...foundTag, ...importedTag });
// Remove the imported Tag
await TagStorage.deleteImportedTag(tenant.id, importedTag.id);
- // Log
- await Logging.logDebug({
- tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_TAGS,
- module: MODULE_NAME, method: 'processTenant',
- message: `Tag ID '${importedTag.id}' has been updated successfully in Tenant ${Utils.buildTenantName(tenant)}`
- });
+ result.inSuccess++;
continue;
}
// New Tag
@@ -58,33 +58,44 @@ export default class ImportTagsTask extends SchedulerTask {
await TagStorage.saveTag(tenant.id, tag);
// Remove the imported Tag
await TagStorage.deleteImportedTag(tenant.id, importedTag.id);
- // Log
- await Logging.logDebug({
- tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_TAGS,
- module: MODULE_NAME, method: 'processTenant',
- message: `Tag ID '${importedTag.id}' have been created in Tenant ${Utils.buildTenantName(tenant)}`
- });
+ result.inSuccess++;
} catch (error) {
// Update the imported Tag
importedTag.status = ImportStatus.ERROR;
importedTag.errorDescription = error.message;
+ result.inError++;
// Update it
await TagStorage.saveImportedTag(tenant.id, importedTag);
// Log
await Logging.logError({
tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_TAGS,
+ action: ServerAction.IMPORT_TAGS,
module: MODULE_NAME, method: 'processTenant',
message: `An error occurred while importing the Tag ID '${importedTag.id}'`,
detailedMessages: { error: error.message, stack: error.stack }
});
}
}
+ // Log
+ if (importedTags.result.length > 0 && (result.inError + result.inSuccess) > 0) {
+ await Logging.logDebug({
+ tenantID: tenant.id,
+ action: ServerAction.IMPORT_TAGS,
+ module: MODULE_NAME, method: 'processTenant',
+ message: `${result.inError + result.inSuccess}/${totalTagsToImport} Tag(s) have been processed`
+ });
+ }
} while (!Utils.isEmptyArray(importedTags?.result));
+ // Log final results
+ await Logging.logActionsResponse(tenant.id, ServerAction.IMPORT_TAGS, MODULE_NAME, 'processTenant', result,
+ `{{inSuccess}} Tag(s) have been imported successfully in Tenant ${Utils.buildTenantName(tenant)}`,
+ `{{inError}} Tag(s) failed to be imported in Tenant ${Utils.buildTenantName(tenant)}`,
+ `{{inSuccess}} Tag(s) have been imported successfully but {{inError}} failed in Tenant ${Utils.buildTenantName(tenant)}`,
+ `Not Tag has been imported in Tenant ${Utils.buildTenantName(tenant)}`
+ );
} catch (error) {
// Log error
- await Logging.logActionExceptionMessage(tenant.id, ServerAction.SYNCHRONIZE_TAGS, error);
+ await Logging.logActionExceptionMessage(tenant.id, ServerAction.IMPORT_TAGS, error);
} finally {
// Release the lock
await LockingManager.release(importTagsLock);

MODIFY
src/scheduler/tasks/ImportUsersTask.ts
src/scheduler/tasks/ImportUsersTask.ts
+import { ActionsResponse, ImportStatus } from '../../types/GlobalType';
import User, { ImportedUser, UserRole, UserStatus } from '../../types/User';
import Constants from '../../utils/Constants';
import { DataResult } from '../../types/DataResult';
import DbParams from '../../types/database/DbParams';
-import { ImportStatus } from '../../types/GlobalType';
import LockingHelper from '../../locking/LockingHelper';
import LockingManager from '../../locking/LockingManager';
import Logging from '../../utils/Logging';
@@ -17,12 +17,18 @@ import Utils from '../../utils/Utils';
const MODULE_NAME = 'SynchronizeUsersImportTask';
export default class ImportUsersTask extends SchedulerTask {
- async processTenant(tenant: Tenant, config: TaskConfig): Promise<void> {
+ public async processTenant(tenant: Tenant, config?: TaskConfig): Promise<void> {
const importUsersLock = await LockingHelper.createImportUsersLock(tenant.id);
if (importUsersLock) {
try {
const dbParams: DbParams = { limit: Constants.IMPORT_PAGE_SIZE, skip: 0 };
let importedUsers: DataResult<ImportedUser>;
+ const result: ActionsResponse = {
+ inError: 0,
+ inSuccess: 0,
+ };
+ // Get total number of Users to import
+ const totalUsersToImport = await UserStorage.getImportedUsersCount(tenant.id);
do {
// Get the imported users
importedUsers = await UserStorage.getImportedUsers(tenant.id, { status: ImportStatus.READY }, dbParams);
@@ -37,13 +43,7 @@ export default class ImportUsersTask extends SchedulerTask {
await UserStorage.saveUser(tenant.id, foundUser);
// Remove the imported User
await UserStorage.deleteImportedUser(tenant.id, importedUser.id);
- // Log
- await Logging.logDebug({
- tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_USERS,
- module: MODULE_NAME, method: 'processTenant',
- message: `User with email '${importedUser.email}' have been updated successfully in Tenant ${Utils.buildTenantName(tenant)}`
- });
+ result.inSuccess++;
continue;
}
// New User
@@ -68,32 +68,43 @@ export default class ImportUsersTask extends SchedulerTask {
await UserStorage.saveUserStatus(tenant.id, user.id, UserStatus.ACTIVE);
// Remove the imported User
await UserStorage.deleteImportedUser(tenant.id, importedUser.id);
- // Log
- await Logging.logDebug({
- tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_USERS,
- module: MODULE_NAME, method: 'processTenant',
- message: `User with email '${importedUser.email}' have been created in Tenant ${Utils.buildTenantName(tenant)}`
- });
+ result.inSuccess++;
} catch (error) {
importedUser.status = ImportStatus.ERROR;
importedUser.errorDescription = error.message;
+ result.inError++;
// Update it
await UserStorage.saveImportedUser(tenant.id, importedUser);
- // Error
+ // Log
await Logging.logError({
tenantID: tenant.id,
- action: ServerAction.SYNCHRONIZE_USERS,
+ action: ServerAction.IMPORT_USERS,
module: MODULE_NAME, method: 'processTenant',
message: `An error occurred when importing user with email '${importedUser.email}'`,
detailedMessages: { error: error.message, stack: error.stack }
});
}
}
+ // Log
+ if (importedUsers.result.length > 0 && (result.inError + result.inSuccess) > 0) {
+ await Logging.logDebug({
+ tenantID: tenant.id,
+ action: ServerAction.IMPORT_USERS,
+ module: MODULE_NAME, method: 'processTenant',
+ message: `${result.inError + result.inSuccess}/${totalUsersToImport} User(s) have been processed`
+ });
+ }
} while (!Utils.isEmptyArray(importedUsers?.result));
+ // Log final results
+ await Logging.logActionsResponse(tenant.id, ServerAction.IMPORT_USERS, MODULE_NAME, 'processTenant', result,
+ `{{inSuccess}} User(s) have been imported successfully in Tenant ${Utils.buildTenantName(tenant)}`,
+ `{{inError}} User(s) failed to be imported in Tenant ${Utils.buildTenantName(tenant)}`,
+ `{{inSuccess}} User(s) have been imported successfully but {{inError}} failed in Tenant ${Utils.buildTenantName(tenant)}`,
+ `Not User has been imported in Tenant ${Utils.buildTenantName(tenant)}`
+ );
} catch (error) {
// Log error
- await Logging.logActionExceptionMessage(tenant.id, ServerAction.SYNCHRONIZE_USERS, error);
+ await Logging.logActionExceptionMessage(tenant.id, ServerAction.IMPORT_USERS, error);
} finally {
// Release the lock
await LockingManager.release(importUsersLock);

MODIFY
src/server/rest/CentralRestServerService.ts
src/server/rest/CentralRestServerService.ts
@@ -95,10 +95,10 @@ class RequestMapper {
[ServerAction.OCPI_ENDPOINT_SEND_EVSE_STATUSES]: OCPIEndpointService.handleSendEVSEStatusesOcpiEndpoint.bind(this),
[ServerAction.OCPI_ENDPOINT_SEND_TOKENS]: OCPIEndpointService.handleSendTokensOcpiEndpoint.bind(this),
[ServerAction.OCPI_ENDPOINT_GENERATE_LOCAL_TOKEN]: OCPIEndpointService.handleGenerateLocalTokenOcpiEndpoint.bind(this),
- [ServerAction.OICP_ENPOINT_CREATE]: OICPEndpointService.handleCreateOicpEndpoint.bind(this),
- [ServerAction.OICP_ENPOINT_PING]: OICPEndpointService.handlePingOicpEndpoint.bind(this),
- [ServerAction.OICP_ENPOINT_SEND_EVSE_STATUSES]: OICPEndpointService.handleSendEVSEStatusesOicpEndpoint.bind(this),
- [ServerAction.OICP_ENPOINT_SEND_EVSES]: OICPEndpointService.handleSendEVSEsOicpEndpoint.bind(this),
+ [ServerAction.OICP_ENDPOINT_CREATE]: OICPEndpointService.handleCreateOicpEndpoint.bind(this),
+ [ServerAction.OICP_ENDPOINT_PING]: OICPEndpointService.handlePingOicpEndpoint.bind(this),
+ [ServerAction.OICP_ENDPOINT_SEND_EVSE_STATUSES]: OICPEndpointService.handleSendEVSEStatusesOicpEndpoint.bind(this),
+ [ServerAction.OICP_ENDPOINT_SEND_EVSES]: OICPEndpointService.handleSendEVSEsOicpEndpoint.bind(this),
[ServerAction.INTEGRATION_CONNECTION_CREATE]: ConnectionService.handleCreateConnection.bind(this),
[ServerAction.CHARGING_STATION_REQUEST_OCPP_PARAMETERS]: ChargingStationService.handleRequestChargingStationOcppParameters.bind(this),
[ServerAction.CAR_CREATE]: CarService.handleCreateCar.bind(this),
@@ -162,7 +162,7 @@ class RequestMapper {
[ServerAction.NOTIFICATIONS]: NotificationService.handleGetNotifications.bind(this),
[ServerAction.TAGS]: TagService.handleGetTags.bind(this),
[ServerAction.TAG]: TagService.handleGetTag.bind(this),
- [ServerAction.USER_DEFAUlT_TAG_CAR]: UserService.handleGetUserDefaultTagCar.bind(this),
+ [ServerAction.USER_DEFAULT_TAG_CAR]: UserService.handleGetUserDefaultTagCar.bind(this),
[ServerAction.TRANSACTIONS_COMPLETED]: TransactionService.handleGetTransactionsCompleted.bind(this),
[ServerAction.TRANSACTIONS_TO_REFUND]: TransactionService.handleGetTransactionsToRefund.bind(this),
[ServerAction.TRANSACTIONS_TO_REFUND_EXPORT]: TransactionService.handleExportTransactionsToRefund.bind(this),

MODIFY
src/server/rest/v1/service/TagService.ts
src/server/rest/v1/service/TagService.ts
@@ -12,6 +12,7 @@ import Authorizations from '../../../../authorization/Authorizations';
import Busboy from 'busboy';
import Constants from '../../../../utils/Constants';
import EmspOCPIClient from '../../../../client/ocpi/EmspOCPIClient';
+import ImportTagsTask from '../../../../scheduler/tasks/ImportTagsTask';
import JSONStream from 'JSONStream';
import LockingHelper from '../../../../locking/LockingHelper';
import LockingManager from '../../../../locking/LockingManager';
@@ -623,6 +624,8 @@ export default class TagService {
}
// Release the lock
await LockingManager.release(importTagsLock);
+ // Trigger manually and asynchronously the job
+ void new ImportTagsTask().processTenant(req.tenant);
// Respond
res.json({ ...result, ...Constants.REST_RESPONSE_SUCCESS });
next();

MODIFY
src/server/rest/v1/service/UserService.ts
src/server/rest/v1/service/UserService.ts
@@ -20,6 +20,7 @@ import Cypher from '../../../../utils/Cypher';
import { DataResult } from '../../../../types/DataResult';
import EmspOCPIClient from '../../../../client/ocpi/EmspOCPIClient';
import I18nManager from '../../../../utils/I18nManager';
+import ImportUsersTask from '../../../../scheduler/tasks/ImportUsersTask';
import JSONStream from 'JSONStream';
import LockingHelper from '../../../../locking/LockingHelper';
import LockingManager from '../../../../locking/LockingManager';
@@ -1021,6 +1022,9 @@ export default class UserService {
}
// Release the lock
await LockingManager.release(importUsersLock);
+ // Trigger manually and asynchronously the job
+ void new ImportUsersTask().processTenant(req.tenant);
+ // Respond
res.json({ ...result, ...Constants.REST_RESPONSE_SUCCESS });
next();
});

MODIFY
src/storage/mongodb/TagStorage.ts
src/storage/mongodb/TagStorage.ts
@@ -104,6 +104,18 @@ export default class TagStorage {
await Logging.traceEnd(tenantID, MODULE_NAME, 'deleteImportedTags', uniqueTimerID);
}
+ public static async getImportedTagsCount(tenantID: string): Promise<number> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getImportedTagsCount');
+ // Check Tenant
+ await DatabaseUtils.checkTenant(tenantID);
+ // Count documents
+ const nbrOfDocuments = await global.database.getCollection<any>(tenantID, 'importedtags').count();
+ // Debug
+ await Logging.traceEnd(tenantID, MODULE_NAME, 'getImportedTagsCount', uniqueTimerID);
+ return nbrOfDocuments;
+ }
+
public static async getImportedTags(tenantID: string,
params: { status?: ImportStatus; search?: string },
dbParams: DbParams, projectFields?: string[]): Promise<DataResult<ImportedTag>> {

MODIFY
src/storage/mongodb/UserStorage.ts
src/storage/mongodb/UserStorage.ts
@@ -715,6 +715,18 @@ export default class UserStorage {
};
}
+ public static async getImportedUsersCount(tenantID: string): Promise<number> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(tenantID, MODULE_NAME, 'getImportedUsersCount');
+ // Check Tenant
+ await DatabaseUtils.checkTenant(tenantID);
+ // Count documents
+ const nbrOfDocuments = await global.database.getCollection<any>(tenantID, 'importedusers').count();
+ // Debug
+ await Logging.traceEnd(tenantID, MODULE_NAME, 'getImportedUsersCount', uniqueTimerID);
+ return nbrOfDocuments;
+ }
+
public static async getImportedUsers(tenantID: string,
params: { status?: ImportStatus; search?: string },
dbParams: DbParams, projectFields?: string[]): Promise<DataResult<ImportedUser>> {

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -153,8 +153,8 @@ export enum ServerAction {
OCPI_ENDPOINT_DELETE = 'OcpiEndpointDelete',
OICP_SETTINGS = 'OicpSettings',
- OICP_ENPOINT_CREATE = 'OicpEndpointCreate',
- OICP_ENPOINT_PING = 'OicpEndpointPing',
+ OICP_ENDPOINT_CREATE = 'OicpEndpointCreate',
+ OICP_ENDPOINT_PING = 'OicpEndpointPing',
OICP_ENDPOINT = 'OicpEndpoint',
OICP_ENDPOINTS = 'OicpEndpoints',
OICP_ENDPOINT_START = 'OicpEndpointStart',
@@ -172,8 +172,8 @@ export enum ServerAction {
OICP_SEND_CHARGING_NOTIFICATION_PROGRESS = 'OicpSendChargingNotificationProgress',
OICP_SEND_CHARGING_NOTIFICATION_END = 'OicpSendChargingNotificationEnd',
OICP_SEND_CHARGING_NOTIFICATION_ERROR = 'OicpSendChargingNotificationError',
- OICP_ENPOINT_SEND_EVSE_STATUSES = 'OicpEndpointSendEVSEStatuses',
- OICP_ENPOINT_SEND_EVSES = 'OicpEndpointSendEVSEs',
+ OICP_ENDPOINT_SEND_EVSE_STATUSES = 'OicpEndpointSendEVSEStatuses',
+ OICP_ENDPOINT_SEND_EVSES = 'OicpEndpointSendEVSEs',
OICP_PUSH_SESSIONS = 'OicpPushSessions',
OICP_CREATE_AXIOS_INSTANCE = 'OicpCreateAxiosInstance',
OICP_ENDPOINT_UPDATE = 'OicpEndpointUpdate',
@@ -380,7 +380,7 @@ export enum ServerAction {
USER_IMAGE = 'UserImage',
TAGS = 'Tags',
TAG = 'Tag',
- USER_DEFAUlT_TAG_CAR = 'UserDefaultTagCar',
+ USER_DEFAULT_TAG_CAR = 'UserDefaultTagCar',
TAG_CREATE = 'TagCreate',
TAG_UPDATE = 'TagUpdate',
TAG_DELETE = 'TagDelete',
@@ -389,8 +389,8 @@ export enum ServerAction {
USER = 'User',
USERS_EXPORT = 'UsersExport',
USERS_IMPORT = 'UsersImport',
- SYNCHRONIZE_USERS = 'SynchronizeUsers',
- SYNCHRONIZE_TAGS = 'SynchronizeTags',
+ IMPORT_USERS = 'ImportUsers',
+ IMPORT_TAGS = 'ImportTags',
NOTIFICATIONS = 'Notifications',

MODIFY
src/utils/Utils.ts
src/utils/Utils.ts
@@ -1338,7 +1338,7 @@ export default class Utils {
}
public static buildTenantName(tenant: Tenant): string {
- return `'${tenant.name}' ('${tenant.subdomain}'`;
+ return `'${tenant.name}' ('${tenant.subdomain}')`;
}
public static isChargingStationIDValid(name: string): boolean {

Trigger manually the job that will import the tags/users after upload. Aligned server actions. Optimized/added meaningful logs to track the current import progress