Added address + logo to tenants
Added endpoint to retrieve logo
MODIFY
src/assets/server/rest/schemas/tenant/tenant-create.json
src/assets/server/rest/schemas/tenant/tenant-create.json
"maxLength": 20,
"sanitize": "mongo"
},
+ "logo": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "address": {
+ "type": "object",
+ "properties": {
+ "address1": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "address2": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "postalCode": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "city": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "department": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "region": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "country": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "coordinates": {
+ "type": "array",
+ "sanitize": "mongo"
+ }
+ }
+ },
"components": {
"type": "object",
"properties": {

MODIFY
src/assets/server/rest/schemas/tenant/tenant-update.json
src/assets/server/rest/schemas/tenant/tenant-update.json
"maxLength": 20,
"sanitize": "mongo"
},
+ "logo": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "address": {
+ "type": "object",
+ "properties": {
+ "address1": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "address2": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "postalCode": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "city": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "department": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "region": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "country": {
+ "type": "string",
+ "sanitize": "mongo"
+ },
+ "coordinates": {
+ "type": "array",
+ "sanitize": "mongo"
+ }
+ }
+ },
"components": {
"type": "object",
"properties": {

MODIFY
src/server/rest/CentralRestServerService.ts
src/server/rest/CentralRestServerService.ts
@@ -140,6 +140,7 @@ class RequestMapper {
[ServerAction.SITE_USERS]: SiteService.handleGetUsers.bind(this),
[ServerAction.TENANTS]: TenantService.handleGetTenants.bind(this),
[ServerAction.TENANT]: TenantService.handleGetTenant.bind(this),
+ [ServerAction.TENANT_LOGO]: TenantService.handleGetTenantLogo.bind(this),
[ServerAction.SITE_AREAS]: SiteAreaService.handleGetSiteAreas.bind(this),
[ServerAction.SITE_AREA]: SiteAreaService.handleGetSiteArea.bind(this),
[ServerAction.SITE_AREA_IMAGE]: SiteAreaService.handleGetSiteAreaImage.bind(this),

MODIFY
src/server/rest/service/TenantService.ts
src/server/rest/service/TenantService.ts
@@ -75,6 +75,21 @@ export default class TenantService {
next();
}
+ public static async handleGetTenantLogo(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
+ // Filter
+ const tenantID = TenantSecurity.filterTenantRequestByID(req.query);
+ // Charge Box is mandatory
+ UtilsService.assertIdIsProvided(action, tenantID, MODULE_NAME, 'handleGetTenantLogo', req.user);
+ // Get it
+ const tenantLogo = await TenantStorage.getTenantLogo(tenantID);
+ // Check
+ UtilsService.assertObjectExists(action, tenantLogo, `Tenant with ID '${tenantID}' does not exist`,
+ MODULE_NAME, 'handleGetTenantLogo', req.user);
+ // Return
+ res.json({ id: tenantLogo.id, logo: tenantLogo.logo });
+ next();
+ }
+
public static async handleGetTenant(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
// Filter
const tenantID = TenantSecurity.filterTenantRequestByID(req.query);

MODIFY
src/server/rest/service/security/TenantSecurity.ts
src/server/rest/service/security/TenantSecurity.ts
@@ -38,6 +38,7 @@ export default class TenantSecurity {
filteredTenant.email = tenant.email;
filteredTenant.subdomain = tenant.subdomain;
filteredTenant.components = tenant.components;
+ filteredTenant.address = tenant.address;
// Created By / Last Changed By
UtilsSecurity.filterCreatedAndLastChanged(

MODIFY
src/storage/mongodb/TenantStorage.ts
src/storage/mongodb/TenantStorage.ts
@@ -36,7 +36,7 @@ export default class TenantStorage {
return tenantsResult.count > 0 ? tenantsResult.result[0] : null;
}
- public static async saveTenant(tenantToSave: Partial<Tenant>): Promise<string> {
+ public static async saveTenant(tenantToSave: Partial<Tenant>, saveLogo = true): Promise<string> {
// Debug
const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'saveTenant');
// Check
@@ -62,14 +62,33 @@ export default class TenantStorage {
name: tenantToSave.name,
email: tenantToSave.email,
subdomain: tenantToSave.subdomain,
- components: tenantToSave.components ? tenantToSave.components : {}
+ components: tenantToSave.components ? tenantToSave.components : {},
};
+ if (tenantToSave.address) {
+ Object.assign(tenantMDB, {
+ address: {
+ address1: tenantToSave.address.address1,
+ address2: tenantToSave.address.address2,
+ postalCode: tenantToSave.address.postalCode,
+ city: tenantToSave.address.city,
+ department: tenantToSave.address.department,
+ region: tenantToSave.address.region,
+ country: tenantToSave.address.country,
+ coordinates: Utils.containsGPSCoordinates(tenantToSave.address.coordinates) ? tenantToSave.address.coordinates.map(
+ (coordinate) => Utils.convertToFloat(coordinate)) : [],
+ }
+ });
+ }
DatabaseUtils.addLastChangedCreatedProps(tenantMDB, tenantToSave);
// Modify
await global.database.getCollection<Tenant>(Constants.DEFAULT_TENANT, 'tenants').findOneAndUpdate(
tenantFilter,
{ $set: tenantMDB },
{ upsert: true, returnOriginal: false });
+ // Save Logo
+ if (saveLogo) {
+ await TenantStorage._saveTenantLogo(tenantMDB._id.toHexString(), tenantToSave.logo);
+ }
// Debug
Logging.traceEnd(MODULE_NAME, 'saveTenant', uniqueTimerID, { tenantToSave });
// Create
@@ -211,4 +230,34 @@ export default class TenantStorage {
// Debug
Logging.traceEnd(MODULE_NAME, 'deleteTenantDB', uniqueTimerID, { id });
}
+
+ public static async getTenantLogo(tenantID: string): Promise<{ id: string; logo: string }> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'getTenantLogo');
+ // Check Tenant
+ await Utils.checkTenant(tenantID);
+ // Read DB
+ const tenantLogoMDB = await global.database.getCollection<{ _id: ObjectID; logo: string }>(Constants.DEFAULT_TENANT, 'tenantlogos')
+ .findOne({ _id: Utils.convertToObjectID(tenantID) });
+ // Debug
+ Logging.traceEnd(MODULE_NAME, 'getTenantLogo', uniqueTimerID, { tenantID });
+ return {
+ id: tenantID,
+ logo: tenantLogoMDB ? tenantLogoMDB.logo : null
+ };
+ }
+
+ private static async _saveTenantLogo(tenantID: string, tenantLogoToSave: string): Promise<void> {
+ // Debug
+ const uniqueTimerID = Logging.traceStart(MODULE_NAME, 'saveTenantLogo');
+ // Check Tenant
+ await Utils.checkTenant(tenantID);
+ // Modify
+ await global.database.getCollection<any>(Constants.DEFAULT_TENANT, 'tenantlogos').findOneAndUpdate(
+ { '_id': Utils.convertToObjectID(tenantID) },
+ { $set: { logo: tenantLogoToSave } },
+ { upsert: true });
+ // Debug
+ Logging.traceEnd(MODULE_NAME, 'saveTenantLogo', uniqueTimerID, {});
+ }
}

MODIFY
src/types/Server.ts
src/types/Server.ts
@@ -277,6 +277,7 @@ export enum ServerAction {
TENANT = 'Tenant',
TENANT_UPDATE = 'TenantUpdate',
TENANT_DELETE = 'TenantDelete',
+ TENANT_LOGO = 'TenantLogo',
COMPANY_CREATE = 'CompanyCreate',
COMPANIES = 'Companies',

MODIFY
src/types/Tenant.ts
src/types/Tenant.ts
+import Address from './Address';
import CreatedUpdatedProps from './CreatedUpdatedProps';
export default interface Tenant extends CreatedUpdatedProps {
@@ -5,6 +6,8 @@ export default interface Tenant extends CreatedUpdatedProps {
name: string;
email: string;
subdomain: string;
+ address: Address;
+ logo?: string;
components: {
ocpi?: {
active: boolean;

MODIFY
test/api/TenantTest.ts
test/api/TenantTest.ts
@@ -42,6 +42,7 @@ describe('Tenant tests', function() {
it('Should update the tenant', async () => {
// Change entity
testData.newTenant.name = 'New Name';
+ testData.newTenant.address.address1 = 'New Address1';
// Update
await CentralServerService.defaultInstance.updateEntity(
CentralServerService.defaultInstance.tenantApi, testData.newTenant);

MODIFY
test/factories/TenantFactory.ts
test/factories/TenantFactory.ts
@@ -4,5 +4,18 @@ import faker from 'faker';
export default Factory.define('tenant')
.attr('name', () => faker.company.companyName())
.attr('email', () => faker.internet.email())
- .attr('subdomain', () => faker.random.alphaNumeric(10).toLowerCase());
+ .attr('subdomain', () => faker.random.alphaNumeric(10).toLowerCase())
+ .attr('address', {
+ address1: faker.address.streetAddress(false),
+ address2: faker.address.streetAddress(true),
+ postalCode: faker.address.zipCode(),
+ city: faker.address.city(10),
+ department: faker.random.alphaNumeric(20),
+ region: faker.random.alphaNumeric(20),
+ country: faker.address.country(),
+ coordinates: [
+ +faker.address.longitude(),
+ +faker.address.latitude()
+ ]
+ });

Added address + logo to tenants
Added endpoint to retrieve logo