@@ -21279,6 +21279,46 @@ class Application {
2127921279 await createAppStreams(this);
2128021280 }
2128121281
21282+ /**
21283+ * Save anything you want for your app
21284+ * @param {Object} content will fully replace any existing content
21285+ */
21286+ async setCustomSettings (content) {
21287+ const currentCustomSettings = await this.getCustomSettings();
21288+ if (currentCustomSettings != null) { // update
21289+ const id = this.cache.customSettingsEvent.id;
21290+ const updatedEvent = await this.connection.apiOne('events.update', { id, update: { content } }, 'event');
21291+ this.cache.customSettingsEvent = updatedEvent;
21292+ } else {
21293+ await this.#createCustomSettings(content);
21294+ }
21295+ return this.cache.customSettingsEvent?.content;
21296+ }
21297+
21298+ /**
21299+ * @private
21300+ * Used by getCustomSettings & setCustomSettings
21301+ * @param {*} content
21302+ */
21303+ async #createCustomSettings (content) {
21304+ const createdEvent = await this.connection.apiOne('events.create', { streamIds: [this.baseStreamId], type: 'settings/any', content }, 'event');
21305+ this.cache.customSettingsEvent = createdEvent;
21306+ }
21307+
21308+ /**
21309+ * Get current settings previously set with setCustomSettings()
21310+ */
21311+ async getCustomSettings (forceRefresh = false) {
21312+ if (forceRefresh || this.cache.customSettingsEvent) {
21313+ const customSettingsEvent = (await this.connection.apiOne('events.get', { streams: [this.baseStreamId], types: ['settings/any'], limit: 1 }, 'events'))[0];
21314+ this.cache.customSettingsEvent = customSettingsEvent;
21315+ }
21316+ if (!this.cache.customSettingsEvent) {
21317+ await this.#createCustomSettings({});
21318+ }
21319+ return this.cache.customSettingsEvent?.content;
21320+ }
21321+
2128221322 /**
2128321323 * Force loading of streamData
2128421324 */
@@ -22716,102 +22756,126 @@ describe('[APAX] Application class', () => {
2271622756 user = await createUserAndPermissions(null, permissionsManager, initialStreams, appName);
2271722757 });
2271822758
22719- it('[APAI] Application extension', async () => {
22720- class Dummy extends Application { }
22759+ describe('[APIX] Application class internal', () => {
22760+ it('[APIS] Application custom settings', async () => {
22761+ class Dummy extends Application {
22762+ get appSettings () {
22763+ return { };
22764+ }
22765+ }
22766+ const appDummy = await Dummy.newFromApiEndpoint(baseStreamId, user.appApiEndpoint, appName);
22767+
22768+ const settings = await appDummy.getCustomSettings();
22769+ assert.deepEqual(settings, {});
22770+ const newSettings = { hello: 'Tom', value: 2 };
22771+ const newSettings1 = await appDummy.setCustomSettings(newSettings);
22772+ assert.deepEqual(newSettings, newSettings1);
22773+ const newSettings2 = await appDummy.getCustomSettings();
22774+ assert.deepEqual(newSettings, newSettings2);
22775+ // assert.equal(newSettings1, newSettings2, 'should be the same object');
22776+ const newSettings3 = await appDummy.getCustomSettings(true);
22777+ assert.deepEqual(newSettings1, newSettings3);
22778+ });
22779+ });
2272122780
22722- try {
22723- await Dummy.newFromApiEndpoint(baseStreamId, user.appApiEndpoint, appName);
22724- throw new Error('Should throw an error');
22725- } catch (e) {
22726- assert.equal(e.message, 'appSettings must be implemented');
22727- }
22781+ describe('[APAE] Application class errors', () => {
22782+ it('[APAI] Application extension', async () => {
22783+ class Dummy extends Application { }
2272822784
22729- try {
22785+ try {
22786+ await Dummy.newFromApiEndpoint(baseStreamId, user.appApiEndpoint, appName);
22787+ throw new Error('Should throw an error');
22788+ } catch (e) {
22789+ assert.equal(e.message, 'appSettings must be implemented');
22790+ }
22791+
22792+ try {
2273022793 // eslint-disable-next-line no-new
22731- new Dummy('u', user.appApiEndpoint, appName);
22732- throw new Error('Should throw an error');
22733- } catch (e) {
22734- assert.equal(e.message, 'Missing or too short baseStreamId');
22735- }
22736- });
22794+ new Dummy('u', user.appApiEndpoint, appName);
22795+ throw new Error('Should throw an error');
22796+ } catch (e) {
22797+ assert.equal(e.message, 'Missing or too short baseStreamId');
22798+ }
22799+ });
2273722800
22738- it('[APAA] Application name form accessInfo fails in not in settings', () => {
22739- class Dummy extends Application {
22740- get appSettings () {
22741- return { };
22801+ it('[APAA] Application name form accessInfo fails in not in settings', () => {
22802+ class Dummy extends Application {
22803+ get appSettings () {
22804+ return { };
22805+ }
2274222806 }
22743- }
2274422807
22745- try {
22808+ try {
2274622809 // eslint-disable-next-line no-new
22747- new Dummy(baseStreamId, user.appApiEndpoint);
22748- throw new Error('Should throw an error');
22749- } catch (e) {
22750- assert.equal(e.message, 'appName must be given unless appSettings.appNameFromAccessInfo = true');
22751- }
22752- });
22810+ new Dummy(baseStreamId, user.appApiEndpoint);
22811+ throw new Error('Should throw an error');
22812+ } catch (e) {
22813+ assert.equal(e.message, 'appName must be given unless appSettings.appNameFromAccessInfo = true');
22814+ }
22815+ });
2275322816
22754- it('[APAB] Application name form accessInfo', async () => {
22755- class Dummy2 extends Application {
22756- get appSettings () {
22757- return {
22758- appNameFromAccessInfo: true
22759- };
22817+ it('[APAB] Application name form accessInfo', async () => {
22818+ class Dummy2 extends Application {
22819+ get appSettings () {
22820+ return {
22821+ appNameFromAccessInfo: true
22822+ };
22823+ }
2276022824 }
22761- }
2276222825
22763- const dummy2 = await Dummy2.newFromApiEndpoint(baseStreamId, user.appApiEndpoint);
22764- assert.ok(dummy2, 'if appSettings.appNameFromAccessInfo = true appName is not required');
22765- });
22826+ const dummy2 = await Dummy2.newFromApiEndpoint(baseStreamId, user.appApiEndpoint);
22827+ assert.ok(dummy2, 'if appSettings.appNameFromAccessInfo = true appName is not required');
22828+ });
2276622829
22767- it('[APAC] Application should throw error if baseStream is not accessible', async () => {
22768- class Dummy extends Application {
22769- get appSettings () {
22770- return { };
22830+ it('[APAC] Application should throw error if baseStream is not accessible', async () => {
22831+ class Dummy extends Application {
22832+ get appSettings () {
22833+ return { };
22834+ }
2277122835 }
22772- }
2277322836
22774- try {
22837+ try {
2277522838 // eslint-disable-next-line no-new
22776- await Dummy.newFromApiEndpoint('uuuu', user.appApiEndpoint, appName);
22777- throw new Error('Should throw an error');
22778- } catch (e) {
22779- assert.equal(e.message, 'Application with "app" type of access requires (streamId = "uuuu", level = "manage") or master access');
22780- }
22781- });
22839+ await Dummy.newFromApiEndpoint('uuuu', user.appApiEndpoint, appName);
22840+ throw new Error('Should throw an error');
22841+ } catch (e) {
22842+ assert.equal(e.message, 'Application with "app" type of access requires (streamId = "uuuu", level = "manage") or master access');
22843+ }
22844+ });
2278222845
22783- it('[APAD] Application should throw error if personaToken are not explicity allowed', async () => {
22784- class Dummy extends Application {
22785- get appSettings () {
22786- return { };
22846+ it('[APAD] Application should throw error if personaToken are not explicity allowed', async () => {
22847+ class Dummy extends Application {
22848+ get appSettings () {
22849+ return { };
22850+ }
2278722851 }
22788- }
2278922852
22790- try {
22853+ try {
2279122854 // eslint-disable-next-line no-new
22792- await Dummy.newFromApiEndpoint('uuuu', user.personalApiEndpoint, appName);
22793- throw new Error('Should throw an error');
22794- } catch (e) {
22795- assert.equal(e.message, 'Application should not use a personal token');
22796- }
22797- });
22855+ await Dummy.newFromApiEndpoint('uuuu', user.personalApiEndpoint, appName);
22856+ throw new Error('Should throw an error');
22857+ } catch (e) {
22858+ assert.equal(e.message, 'Application should not use a personal token');
22859+ }
22860+ });
2279822861
22799- it('[APAE] Application should throw error if master token not provided and required', async () => {
22800- class Dummy extends Application {
22801- get appSettings () {
22802- return {
22803- mustBemaster: true
22804- };
22862+ it('[APAE] Application should throw error if master token not provided and required', async () => {
22863+ class Dummy extends Application {
22864+ get appSettings () {
22865+ return {
22866+ mustBemaster: true
22867+ };
22868+ }
2280522869 }
22806- }
2280722870
22808- try {
22871+ try {
2280922872 // eslint-disable-next-line no-new
22810- await Dummy.newFromApiEndpoint('uuuu', user.appApiEndpoint, appName);
22811- throw new Error('Should throw an error');
22812- } catch (e) {
22813- assert.equal(e.message, 'Application with "app" type of access requires "master" token (streamId = "*", level = "manage")');
22814- }
22873+ await Dummy.newFromApiEndpoint('uuuu', user.appApiEndpoint, appName);
22874+ throw new Error('Should throw an error');
22875+ } catch (e) {
22876+ assert.equal(e.message, 'Application with "app" type of access requires "master" token (streamId = "*", level = "manage")');
22877+ }
22878+ });
2281522879 });
2281622880});
2281722881
0 commit comments