Skip to content

Commit

Permalink
Merge branch 'develop' into regression/apps-provider-behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Mar 4, 2023
2 parents 4e84f1f + 5e6015e commit 016d53a
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 30 deletions.
20 changes: 12 additions & 8 deletions apps/meteor/ee/app/license/server/lib/isUnderAppLimits.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager';
import { Apps } from '@rocket.chat/core-services';

import type { ILicense, LicenseAppSources } from '../../definition/ILicense';

export async function isUnderAppLimits(
{ appManager }: { appManager: AppManager },
licenseAppsConfig: NonNullable<ILicense['apps']>,
source: LicenseAppSources,
): Promise<boolean> {
const apps = appManager.get({ enabled: true }).filter((app) => app.getStorageItem().installationSource === source);
export async function isUnderAppLimits(licenseAppsConfig: NonNullable<ILicense['apps']>, source: LicenseAppSources): Promise<boolean> {
const apps = await Apps.getApps({ enabled: true });

if (!apps || !Array.isArray(apps)) {
return true;
}

const storageItems = await Promise.all(apps.map((app) => Apps.getAppStorageItemById(app.id)));
const activeAppsFromSameSource = storageItems.filter((item) => item?.installationSource === source);

const configKey = `max${source.charAt(0).toUpperCase()}${source.slice(1)}Apps` as keyof typeof licenseAppsConfig;
const configLimit = licenseAppsConfig[configKey];

Expand All @@ -17,5 +21,5 @@ export async function isUnderAppLimits(
return true;
}

return apps.length < configLimit;
return activeAppsFromSameSource.length < configLimit;
}
23 changes: 3 additions & 20 deletions apps/meteor/ee/app/license/server/license.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter } from 'events';

import type { AppManager } from '@rocket.chat/apps-engine/server/AppManager';
import { Apps } from '@rocket.chat/core-services';
import type { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage';

import { Users } from '../../../../app/models/server';
Expand All @@ -11,7 +11,6 @@ import { getTagColor } from './getTagColor';
import type { ILicense, LicenseAppSources } from '../definition/ILicense';
import type { ILicenseTag } from '../definition/ILicenseTag';
import { isUnderAppLimits } from './lib/isUnderAppLimits';
import type { AppServerOrchestrator } from '../../../server/apps/orchestrator';

const EnterpriseLicenses = new EventEmitter();

Expand Down Expand Up @@ -39,22 +38,6 @@ class LicenseClass {
maxMarketplaceApps: 5,
};

private Apps: AppServerOrchestrator;

constructor() {
/**
* Importing the Apps variable statically at the top of the file causes a change
* in the import order and ends up causing an error during the server initialization
*
* We added a dynamic import here to avoid this issue
* @TODO as soon as the Apps-Engine service is available, use it instead of this dynamic import
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
import('../../../server/apps').then(({ Apps }) => {
this.Apps = Apps;
});
}

private _validateExpiration(expiration: string): boolean {
return new Date() > new Date(expiration);
}
Expand Down Expand Up @@ -237,11 +220,11 @@ class LicenseClass {
}

async canEnableApp(source: LicenseAppSources): Promise<boolean> {
if (!this.Apps?.isInitialized()) {
if (!Apps.isInitialized()) {
return false;
}

return isUnderAppLimits({ appManager: this.Apps.getManager() as AppManager }, this.appsConfig, source);
return isUnderAppLimits(this.appsConfig, source);
}

showLicenses(): void {
Expand Down
23 changes: 23 additions & 0 deletions apps/meteor/server/services/apps-engine/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import type { IAppsEngineService } from '@rocket.chat/core-services';
import type { AppStatus } from '@rocket.chat/apps-engine/definition/AppStatus';
import { AppStatusUtils } from '@rocket.chat/apps-engine/definition/AppStatus';
import type { ISetting } from '@rocket.chat/core-typings';
import type { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage';
import type { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';
import type { IGetAppsFilter } from '@rocket.chat/apps-engine/server/IGetAppsFilter';

import { Apps, AppEvents } from '../../../ee/server/apps/orchestrator';
import { AppEvents as AppLifeCycleEvents } from '../../../ee/server/apps/communication/websockets';
Expand Down Expand Up @@ -104,4 +107,24 @@ export class AppsEngineService extends ServiceClassInternal implements IAppsEngi
notifications.streamApps.emitWithoutBroadcast(AppLifeCycleEvents.ACTIONS_CHANGED);
});
}

isInitialized(): boolean {
return Apps.isInitialized();
}

async getApps(query: IGetAppsFilter): Promise<IAppInfo[] | undefined> {
return Apps.getManager()
?.get(query)
.map((app) => app.getApp().getInfo());
}

async getAppStorageItemById(appId: string): Promise<IAppStorageItem | undefined> {
const app = Apps.getManager()?.getOneById(appId);

if (!app) {
return;
}

return app.getStorageItem();
}
}
1 change: 1 addition & 0 deletions packages/core-services/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export {

// TODO think in a way to not have to pass the service name to proxify here as well
export const Authorization = proxifyWithWait<IAuthorization>('authorization');
export const Apps = proxifyWithWait<IAppsEngineService>('apps-engine');
export const Presence = proxifyWithWait<IPresence>('presence');
export const Account = proxifyWithWait<IAccount>('accounts');
export const License = proxifyWithWait<ILicense>('license');
Expand Down
10 changes: 8 additions & 2 deletions packages/core-services/src/types/IAppsEngineService.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import type { IServiceClass } from './ServiceClass';
import type { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata';
import type { IAppStorageItem } from '@rocket.chat/apps-engine/server/storage';
import type { IGetAppsFilter } from '@rocket.chat/apps-engine/server/IGetAppsFilter';

export type IAppsEngineService = IServiceClass;
export interface IAppsEngineService {
isInitialized(): boolean;
getApps(query: IGetAppsFilter): Promise<IAppInfo[] | undefined>;
getAppStorageItemById(appId: string): Promise<IAppStorageItem | undefined>;
}

0 comments on commit 016d53a

Please sign in to comment.