Use the same TagImport approach in UserImport
MODIFY
src/async-task/tasks/ImportAsyncTask.ts
src/async-task/tasks/ImportAsyncTask.ts
+import Tag, { ImportedTag } from '../../types/Tag';
import User, { ImportedUser, UserRole, UserStatus } from '../../types/User';
import AbstractAsyncTask from '../AsyncTask';
import Constants from '../../utils/Constants';
-import { ImportedTag } from '../../types/Tag';
import Logging from '../../utils/Logging';
import NotificationHandler from '../../notification/NotificationHandler';
import { ServerAction } from '../../types/Server';
import Site from '../../types/Site';
import SiteStorage from '../../storage/mongodb/SiteStorage';
+import TagStorage from '../../storage/mongodb/TagStorage';
import Tenant from '../../types/Tenant';
import TenantComponents from '../../types/TenantComponents';
import UserStorage from '../../storage/mongodb/UserStorage';
@@ -20,8 +21,8 @@ export default abstract class ImportAsyncTask extends AbstractAsyncTask {
private existingAutoAssignableSites: Map<string, Site> = new Map();
private existingSites: Map<string, Site> = new Map();
- protected async processImportedUser(tenant: Tenant, importedUser: ImportedUser|ImportedTag): Promise<User> {
- // Existing Users
+ protected async processImportedUser(tenant: Tenant, importedUser: ImportedUser): Promise<User> {
+ // Get User
let user = await UserStorage.getUserByEmail(tenant.id, importedUser.email);
if (user) {
await this.updateUser(tenant, user, importedUser);
@@ -34,7 +35,72 @@ export default abstract class ImportAsyncTask extends AbstractAsyncTask {
return user;
}
- private async updateUser(tenant: Tenant, user: User, importedUser: ImportedUser|ImportedTag): Promise<void> {
+ protected async processImportedTag(tenant: Tenant, importedTag: ImportedTag): Promise<Tag> {
+ // Get Tag
+ let tag = await TagStorage.getTag(tenant.id, importedTag.id, { withNbrTransactions: true });
+ // Try to get Tag with Visual ID
+ if (!tag && importedTag.visualID) {
+ tag = await TagStorage.getTagByVisualID(tenant.id, importedTag.visualID, { withNbrTransactions: true });
+ }
+ if (tag) {
+ this.updateTag(tag, importedTag);
+ } else {
+ tag = this.createTag(importedTag);
+ }
+ // Save user if any and get the ID to assign tag
+ if (importedTag.email && importedTag.name && importedTag.firstName) {
+ // Check & Import the User
+ const user = await this.processImportedUser(tenant, importedTag as ImportedUser);
+ // Assign
+ tag.userID = user.id;
+ // Make this Tag default
+ await TagStorage.clearDefaultUserTag(tenant.id, user.id);
+ tag.default = true;
+ }
+ // Save the new Tag
+ await TagStorage.saveTag(tenant.id, tag);
+ return tag;
+ }
+
+ private updateTag(tag: Tag, importedTag: ImportedTag): void {
+ // Check tag is already in use
+ if (!tag.issuer) {
+ throw new Error('Tag is not local to the organization');
+ }
+ if (tag.userID) {
+ throw new Error('Tag is already assigned to a user');
+ }
+ if (tag.active) {
+ throw new Error('Tag is already active');
+ }
+ if (tag.transactionsCount > 0) {
+ throw new Error(`Tag is already used in ${tag.transactionsCount} transaction(s)`);
+ }
+ if (tag.id !== importedTag.id) {
+ throw new Error('Tag Visual ID is already assigned to another tag');
+ }
+ // Update
+ tag.visualID = importedTag.visualID;
+ tag.active = importedTag.importedData?.autoActivateTagAtImport;
+ tag.description = importedTag.description;
+ tag.importedData = importedTag.importedData;
+ }
+
+ private createTag(importedTag: ImportedTag): Tag {
+ // New Tag
+ return {
+ id: importedTag.id,
+ visualID: importedTag.visualID,
+ description: importedTag.description,
+ issuer: true,
+ active: importedTag.importedData?.autoActivateTagAtImport,
+ createdBy: { id: importedTag.importedBy },
+ createdOn: importedTag.importedOn,
+ importedData: importedTag.importedData
+ };
+ }
+
+ private async updateUser(tenant: Tenant, user: User, importedUser: ImportedUser): Promise<void> {
// Check user is already in use
if (!user.issuer) {
throw new Error('User is not local to the organization');
@@ -45,7 +111,7 @@ export default abstract class ImportAsyncTask extends AbstractAsyncTask {
await UserStorage.saveUser(tenant.id, user);
}
- private async createUser(tenant: Tenant, importedUser: ImportedUser|ImportedTag): Promise<User> {
+ private async createUser(tenant: Tenant, importedUser: ImportedUser): Promise<User> {
// New User
const newUser = UserStorage.createNewUser() as User;
// Set
@@ -63,7 +129,7 @@ export default abstract class ImportAsyncTask extends AbstractAsyncTask {
return newUser;
}
- private async processSiteAssignment(tenant: Tenant, user: User, importedUser: ImportedUser|ImportedTag): Promise<void> {
+ private async processSiteAssignment(tenant: Tenant, user: User, importedUser: ImportedUser): Promise<void> {
// If we never got the sites from db -> construct array of existing sites that are autoassignable
if (Utils.isEmptyArray(this.existingAutoAssignableSites)) {
// Init Site collections
@@ -104,26 +170,26 @@ export default abstract class ImportAsyncTask extends AbstractAsyncTask {
}
}
- private async sendNotifications(tenant: Tenant, newUser: User): Promise<void> {
+ private async sendNotifications(tenant: Tenant, user: User): Promise<void> {
// Handle sending email for reseting password if user auto activated
// Init Password info
const resetHash = Utils.generateUUID();
- await UserStorage.saveUserPassword(tenant.id, newUser.id, { passwordResetHash: resetHash });
+ await UserStorage.saveUserPassword(tenant.id, user.id, { passwordResetHash: resetHash });
// Generate new verificationToken
- const verificationToken = Utils.generateToken(newUser.email);
+ const verificationToken = Utils.generateToken(user.email);
// Save User Verification Account
- await UserStorage.saveUserAccountVerification(tenant.id, newUser.id, { verificationToken });
+ await UserStorage.saveUserAccountVerification(tenant.id, user.id, { verificationToken });
// Build account verif email with reset password embeded
const evseDashboardVerifyEmailURL = Utils.buildEvseURL(tenant.subdomain) +
- '/verify-email?VerificationToken=' + verificationToken + '&Email=' + newUser.email + '&ResetToken=' + resetHash;
+ '/verify-email?VerificationToken=' + verificationToken + '&Email=' + user.email + '&ResetToken=' + resetHash;
// Send activate account link
await NotificationHandler.sendVerificationEmailUserImport(
tenant.id,
Utils.generateUUID(),
- newUser,
+ user,
{
'tenantName': tenant.name,
- 'user': newUser,
+ 'user': user,
'evseDashboardURL': Utils.buildEvseURL(tenant.subdomain),
'evseDashboardVerifyEmailURL': evseDashboardVerifyEmailURL
});

MODIFY
src/async-task/tasks/TagsImportAsyncTask.ts
src/async-task/tasks/TagsImportAsyncTask.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 ImportAsyncTask from './ImportAsyncTask';
+import { ImportedTag } from '../../types/Tag';
import LockingHelper from '../../locking/LockingHelper';
import LockingManager from '../../locking/LockingManager';
import Logging from '../../utils/Logging';
@@ -41,58 +41,10 @@ export default class TagsImportAsyncTask extends ImportAsyncTask {
do {
// Get the imported tags
importedTags = await TagStorage.getImportedTags(tenant.id, { status: ImportStatus.READY }, dbParams);
- let tagToSave: Tag;
for (const importedTag of importedTags.result) {
try {
- // Get Tag
- let foundTag = await TagStorage.getTag(tenant.id, importedTag.id, { withNbrTransactions: true });
- // Try to get Tag with Visual ID
- if (!foundTag && importedTag.visualID) {
- foundTag = await TagStorage.getTagByVisualID(tenant.id, importedTag.visualID, { withNbrTransactions: true });
- }
- if (foundTag) {
- // Check tag is already in use
- if (!foundTag.issuer) {
- throw new Error('Tag is not local to the organization');
- }
- if (foundTag.userID) {
- throw new Error('Tag is already assigned to a user');
- }
- if (foundTag.active) {
- throw new Error('Tag is already active');
- }
- if (foundTag.transactionsCount > 0) {
- throw new Error(`Tag is already used in ${foundTag.transactionsCount} transaction(s)`);
- }
- if (foundTag.id !== importedTag.id) {
- throw new Error('Tag Visual ID is already assigned to another tag');
- }
- tagToSave = { ...foundTag, ...importedTag };
- } else {
- // New Tag
- tagToSave = {
- id: importedTag.id,
- visualID: importedTag.visualID,
- description: importedTag.description,
- issuer: true,
- active: importedTag.importedData.autoActivateTagAtImport,
- createdBy: { id: importedTag.importedBy },
- createdOn: importedTag.importedOn,
- importedData: importedTag.importedData
- };
- }
- // Save user if any and get the ID to assign tag
- if (importedTag.email && importedTag.name && importedTag.firstName) {
- // Check & Import the User
- const user = await this.processImportedUser(tenant, importedTag);
- // Assign
- tagToSave.userID = user.id;
- // Make this Tag default
- await TagStorage.clearDefaultUserTag(tenant.id, user.id);
- tagToSave.default = true;
- }
- // Save the new Tag
- await TagStorage.saveTag(tenant.id, tagToSave);
+ // Check & Import the Tag
+ await this.processImportedTag(tenant, importedTag);
// Remove the imported Tag
await TagStorage.deleteImportedTag(tenant.id, importedTag.id);
result.inSuccess++;

MODIFY
src/async-task/tasks/UsersImportAsyncTask.ts
src/async-task/tasks/UsersImportAsyncTask.ts
@@ -43,28 +43,27 @@ export default class UsersImportAsyncTask extends ImportAsyncTask {
importedUsers = await UserStorage.getImportedUsers(tenant.id, { status: ImportStatus.READY }, dbParams);
for (const importedUser of importedUsers.result) {
try {
- // if user not found we create one
+ // Check & Import the User
await this.processImportedUser(tenant, importedUser);
// Remove the imported User either it's found or not
await UserStorage.deleteImportedUser(tenant.id, importedUser.id);
result.inSuccess++;
} catch (error) {
+ // Mark the imported User faulty with the reason
importedUser.status = ImportStatus.ERROR;
importedUser.errorDescription = error.message;
result.inError++;
// Update it
await UserStorage.saveImportedUser(tenant.id, importedUser);
- // Log
await Logging.logError({
tenantID: tenant.id,
action: ServerAction.USERS_IMPORT,
module: MODULE_NAME, method: 'executeAsyncTask',
- message: `Error when importing User with email '${importedUser.email}': ${error.message}`,
- detailedMessages: { user: importedUser, error: error.stack }
+ message: `Cannot import User with email '${importedUser.email}': ${error.message}`,
+ detailedMessages: { importedUser, error: error.stack }
});
}
}
- // Log
if (importedUsers.result.length > 0 && (result.inError + result.inSuccess) > 0) {
const intermediateDurationSecs = Math.round((new Date().getTime() - startTime) / 1000);
await Logging.logDebug({

Use the same TagImport approach in UserImport