diff --git a/lib/util/settings.js b/lib/util/settings.js index b2b4074c..a0b3441d 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -262,6 +262,16 @@ function write() { function validate() { const validate = ajv.compile(schema); const valid = validate(_settings); + + // Verify that all friendly names are unique + const names = []; + const check = (name) => { + if (names.includes(name)) throw new Error(`Duplicate friendly_name '${name}' found`); + names.push(name); + }; + Object.values(_settingsWithDefaults.devices).forEach((d) => check(d.friendly_name)); + Object.values(_settingsWithDefaults.groups).forEach((g) => check(g.friendly_name)); + return !valid ? validate.errors.map((v) => `${v.dataPath.substring(1)} ${v.message}`) : null; } @@ -444,8 +454,8 @@ function removeDevice(IDorName) { } function addGroup(name) { - if (getGroup(name)) { - throw new Error(`Group '${name}' already exists`); + if (getGroup(name) || getDevice(name)) { + throw new Error(`friendly_name '${name}' is already in use`); } const settings = get(); @@ -524,6 +534,10 @@ function changeDeviceOptions(IDorName, newOptions) { } function changeFriendlyName(IDorName, newName) { + if (getGroup(newName) || getDevice(newName)) { + throw new Error(`friendly_name '${newName}' is already in use`); + } + const device = getDeviceThrowIfNotExists(IDorName); const settings = get(); settings.devices[device.ID].friendly_name = newName; diff --git a/test/settings.test.js b/test/settings.test.js index aa5e43ec..d18e1fa6 100644 --- a/test/settings.test.js +++ b/test/settings.test.js @@ -312,7 +312,7 @@ describe('Settings', () => { settings.addGroup('test123'); expect(() => { settings.addGroup('test123'); - }).toThrow(new Error("Group 'test123' already exists")); + }).toThrow(new Error("friendly_name 'test123' is already in use")); const expected = { '1': { friendly_name: 'test123', @@ -435,4 +435,32 @@ describe('Settings', () => { expect(error.message).toContain(`no such file or directory, open`); }); + + it('Configuration shouldnt be valid when duplicate friendly_name are used', async () => { + write(configurationFile, { + devices: {'0x0017880104e45519': {friendly_name: 'myname', retain: false}}, + groups: {'1': {friendly_name: 'myname', retain: false}}, + }); + + settings._reRead(); + + expect(() => { + settings.validate(); + }).toThrowError(`Duplicate friendly_name 'myname' found`); + }); + + it('Configuration shouldnt be valid when duplicate friendly_name are used', async () => { + write(configurationFile, { + devices: { + '0x0017880104e45519': {friendly_name: 'myname', retain: false}, + '0x0017880104e45511': {friendly_name: 'myname1', retain: false} + }, + }); + + settings._reRead(); + + expect(() => { + settings.changeFriendlyName('myname1', 'myname'); + }).toThrowError(`friendly_name 'myname' is already in use`); + }); });