Avoid sending name+email on user updates
MODIFY
src/assets/server/rest/v1/docs/e-mobility-oas.json
src/assets/server/rest/v1/docs/e-mobility-oas.json
"content": {
"application/json": {
"schema": {
- "$ref": "#/components/schemas/User"
+ "type": "object",
+ "properties": {
+ "costCenter": {
+ "type": "string",
+ "example": "######"
+ },
+ "name": {
+ "type": "string",
+ "example": "Demo"
+ },
+ "firstName": {
+ "type": "string",
+ "example": "User"
+ },
+ "iNumber": {
+ "type": "string",
+ "example": "1234567"
+ },
+ "image": {
+ "type": "string"
+ },
+ "mobile": {
+ "type": "string",
+ "example": "0000000000"
+ },
+ "locale": {
+ "type": "string",
+ "example": "en_EN"
+ },
+ "address": {
+ "$ref": "#/components/schemas/Address"
+ },
+ "password": {
+ "type": "string",
+ "example": "DeM*Us$r1"
+ },
+ "phone": {
+ "type": "string",
+ "example": "0000000000"
+ },
+ "email": {
+ "type": "string",
+ "example": "user.demo@sap.com"
+ },
+ "issuer": {
+ "type": "boolean"
+ },
+ "notifcationsActive": {
+ "type": "boolean"
+ },
+ "status": {
+ "type": "string",
+ "enum": [
+ "P",
+ "A",
+ "I",
+ "B",
+ "L"
+ ]
+ },
+ "plateID": {
+ "type": "string",
+ "example": "DEMO"
+ },
+ "role": {
+ "type": "string",
+ "enum": [
+ "S",
+ "A",
+ "B",
+ "D"
+ ],
+ "example": "B"
+ },
+ "notifications": {
+ "$ref": "#/components/schemas/Notifications"
+ }
+ }
}
}
}

MODIFY
src/assets/server/rest/v1/schemas/user/user-update.json
src/assets/server/rest/v1/schemas/user/user-update.json
}
},
"required": [
- "id",
- "name",
- "email"
+ "id"
]
}

MODIFY
src/server/rest/v1/service/UserService.ts
src/server/rest/v1/service/UserService.ts
@@ -168,6 +168,7 @@ export default class UserService {
let user = await UtilsService.checkAndGetUserAuthorization(
req.tenant, req.user, filteredRequest.id, Action.UPDATE, action, filteredRequest);
// Check email already exists
+ if (filteredRequest.email) {
const userWithEmail = await UserStorage.getUserByEmail(req.tenant, filteredRequest.email);
if (userWithEmail && user.id !== userWithEmail.id) {
throw new AppError({
@@ -179,6 +180,7 @@ export default class UserService {
action: action
});
}
+ }
// Check if Status has been changed
if (filteredRequest.status && filteredRequest.status !== user.status) {
statusHasChanged = true;
@@ -192,11 +194,15 @@ export default class UserService {
user = {
...user,
...filteredRequest,
- name: filteredRequest.name.toUpperCase(),
- email: filteredRequest.email.toLowerCase(),
lastChangedBy: lastChangedBy,
lastChangedOn: lastChangedOn,
};
+ if (filteredRequest.name) {
+ user.name = filteredRequest.name.toUpperCase();
+ }
+ if (filteredRequest.email) {
+ user.email = filteredRequest.email.toLowerCase();
+ }
// Update User (override TagIDs because it's not of the same type as in filteredRequest)
await UserStorage.saveUser(req.tenant, user, true);
// Save User's password

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
@@ -1484,7 +1484,7 @@ export default class UtilsService {
actionOnUser: filteredRequest.id
});
}
- if (!filteredRequest.name) {
+ if (req.method === 'POST' && !filteredRequest.name) {
throw new AppError({
source: Constants.CENTRAL_SERVER,
errorCode: HTTPError.GENERAL_ERROR,

MODIFY
test/api/OCPPCommonTests.ts
test/api/OCPPCommonTests.ts
@@ -438,7 +438,7 @@ export default class OCPPCommonTests {
'connectorId': this.chargingStationContext.getChargingStation().connectors[0].connectorId
}
});
- expect(response.status).to.equal(570);
+ expect(response.status).to.equal(StatusCodes.INTERNAL_SERVER_ERROR);
}
public async testRemoteStartTransactionWithExternalUser() {

MODIFY
test/api/UserTest.ts
test/api/UserTest.ts
+import User, { UserRole } from '../../src/types/User';
import chai, { assert, expect } from 'chai';
import CentralServerService from '../api/client/CentralServerService';
@@ -14,7 +15,6 @@ import { StatusCodes } from 'http-status-codes';
import Tag from '../../src/types/Tag';
import TenantContext from './context/TenantContext';
import TestUtils from './TestUtils';
-import User from '../../src/types/User';
import chaiSubset from 'chai-subset';
import moment from 'moment';
import responseHelper from '../helpers/responseHelper';
@@ -170,6 +170,20 @@ describe('User', function() {
);
});
+ it('Should be able to update the user with a single attribute in the request', async () => {
+ // Update
+ await testData.userService.updateEntity(
+ testData.userService.userApi,
+ { id: testData.newUser.id, role: UserRole.ADMIN }
+ );
+
+ testData.newUser = (await testData.userService.getEntityById(
+ testData.userService.userApi,
+ testData.newUser,
+ false
+ )).data;
+ });
+
it('Should be able to create a tag for user', async () => {
testData.newTag = Factory.tag.build({ userID: testData.newUser.id });
const response = await testData.userService.userApi.createTag(testData.newTag);

Avoid sending name+email on user updates