diff --git a/src/definition/accessors/IRead.ts b/src/definition/accessors/IRead.ts index e7ed55c4c..66c229050 100644 --- a/src/definition/accessors/IRead.ts +++ b/src/definition/accessors/IRead.ts @@ -4,6 +4,7 @@ import { IMessageRead } from './IMessageRead'; import { INotifier } from './INotifier'; import { IPersistenceRead } from './IPersistenceRead'; import { IRoomRead } from './IRoomRead'; +import { IRoomSubscriptionRead } from './IRoomSubscriptionRead'; import { IUploadRead } from './IUploadRead'; import { IUserRead } from './IUserRead'; @@ -25,6 +26,9 @@ export interface IRead { /** Gets the IRoomRead instance. */ getRoomReader(): IRoomRead; + /** Gets the IRoomSubscriptionRead instance. */ + getRoomSubscriptionReader(): IRoomSubscriptionRead; + /** Gets the IUserRead instance. */ getUserReader(): IUserRead; diff --git a/src/definition/accessors/IRoomSubscriptionRead.ts b/src/definition/accessors/IRoomSubscriptionRead.ts new file mode 100644 index 000000000..263a184e5 --- /dev/null +++ b/src/definition/accessors/IRoomSubscriptionRead.ts @@ -0,0 +1,23 @@ +import { IRoomSubscription } from '../subscriptions'; + +/** + * This accessor provides methods for accessing + * subscriptions in a read-only-fashion. + */ +export interface IRoomSubscriptionRead { + /** + * Gets a list of subscriptions by a room id. + * + * @param roomId the id of the room + * @returns an iterator of subscriptions + */ + getByRoomId(roomId: string): Promise>; + + /** + * Gets a list of all the subscriptions for a user by their id. + * + * @param userId the id of the user + * @returns an iterator of subscriptions for the user + */ + getByUserId(userId: string): Promise>; +} diff --git a/src/definition/accessors/index.ts b/src/definition/accessors/index.ts index 690158bd1..ae4dd4c62 100644 --- a/src/definition/accessors/index.ts +++ b/src/definition/accessors/index.ts @@ -36,6 +36,7 @@ import { IRead } from './IRead'; import { IRoomBuilder } from './IRoomBuilder'; import { IRoomExtender } from './IRoomExtender'; import { IRoomRead } from './IRoomRead'; +import { IRoomSubscriptionRead } from './IRoomSubscriptionRead'; import { IServerSettingRead } from './IServerSettingRead'; import { IServerSettingsModify } from './IServerSettingsModify'; import { ISettingRead } from './ISettingRead'; @@ -82,6 +83,7 @@ export { IRoomBuilder, IRoomExtender, IRoomRead, + IRoomSubscriptionRead, IServerSettingRead, IServerSettingsModify, ISettingRead, diff --git a/src/definition/subscriptions/IRoomSubscription.ts b/src/definition/subscriptions/IRoomSubscription.ts new file mode 100644 index 000000000..d1c1ee9ea --- /dev/null +++ b/src/definition/subscriptions/IRoomSubscription.ts @@ -0,0 +1,32 @@ +import { IRoom } from '../rooms'; +import { IUser } from '../users'; + +/** + * This interface represents a user's subscription to + * a room and includes information about that user's + * settings and information in relation to the room. + */ +export interface IRoomSubscription { + /** The id of the subscription (maps to `_id`). */ + id: string; + /** The room the subscription is for (kinda maps to `rid`). */ + room: IRoom; + /** The user the subscription is for (kinda maps to `u`). */ + user: IUser; + /** Whether the room the subscription is for is hidden from the UI (maps to `open`). */ + isHidden: boolean; + /** Whether the subscription has an alert or notification for the user (maps to `alert`). */ + hasAlert: boolean; + /** The actual number to display on the room's list; it is the sum of userMentionsCount and groupMentionsCount (maps to `unread`). */ + unreadCount: number; + /** The number of times the user has been mentioned (maps to `userMentions`). */ + userMentionsCount: number; + /** The number of times the groups a user is part of has been mentioned (maps to `groupMentions`). */ + groupMentionsCount: number; + /** The date when the subscription was created (maps to `ts`). */ + createdAt: Date; + /** The date when the subscription was last updated (maps to `_updatedAt`). */ + updatedAt?: Date; + /** The last date/time the subscription was seen or marked as read (maps to `ls`). */ + lastSeenAt?: Date; +} diff --git a/src/definition/subscriptions/index.ts b/src/definition/subscriptions/index.ts new file mode 100644 index 000000000..9ea23bb06 --- /dev/null +++ b/src/definition/subscriptions/index.ts @@ -0,0 +1 @@ +export { IRoomSubscription } from './IRoomSubscription'; diff --git a/src/server/accessors/Reader.ts b/src/server/accessors/Reader.ts index ad490b061..e0e12dffe 100644 --- a/src/server/accessors/Reader.ts +++ b/src/server/accessors/Reader.ts @@ -6,6 +6,7 @@ import { IPersistenceRead, IRead, IRoomRead, + IRoomSubscriptionRead, IUploadRead, IUserRead, } from '../../definition/accessors'; @@ -16,6 +17,7 @@ export class Reader implements IRead { private message: IMessageRead, private persist: IPersistenceRead, private room: IRoomRead, + private roomSubscription: IRoomSubscriptionRead, private user: IUserRead, private noti: INotifier, private livechat: ILivechatRead, @@ -38,6 +40,10 @@ export class Reader implements IRead { return this.room; } + public getRoomSubscriptionReader(): IRoomSubscriptionRead { + return this.roomSubscription; + } + public getUserReader(): IUserRead { return this.user; } diff --git a/src/server/accessors/RoomSubscriptionRead.ts b/src/server/accessors/RoomSubscriptionRead.ts new file mode 100644 index 000000000..2cae8a5d6 --- /dev/null +++ b/src/server/accessors/RoomSubscriptionRead.ts @@ -0,0 +1,16 @@ +import { IRoomSubscriptionRead } from '../../definition/accessors'; +import { IRoomSubscription } from '../../definition/subscriptions'; + +import { IRoomSubscriptionBridge } from '../bridges'; + +export class RoomSubscriptionRead implements IRoomSubscriptionRead { + constructor(private subscriptionBridge: IRoomSubscriptionBridge, private appId: string) { } + + public getByRoomId(roomId: string): Promise> { + return this.subscriptionBridge.getByRoomId(roomId, this.appId); + } + + public getByUserId(userId: string): Promise> { + return this.subscriptionBridge.getByUserId(userId, this.appId); + } +} diff --git a/src/server/accessors/index.ts b/src/server/accessors/index.ts index 43e5cb1f4..ff44dc1db 100644 --- a/src/server/accessors/index.ts +++ b/src/server/accessors/index.ts @@ -22,6 +22,7 @@ import { Reader } from './Reader'; import { RoomBuilder } from './RoomBuilder'; import { RoomExtender } from './RoomExtender'; import { RoomRead } from './RoomRead'; +import { RoomSubscriptionRead } from './RoomSubscriptionRead'; import { ServerSettingRead } from './ServerSettingRead'; import { ServerSettingsModify } from './ServerSettingsModify'; import { SettingRead } from './SettingRead'; @@ -57,6 +58,7 @@ export { RoomBuilder, RoomExtender, RoomRead, + RoomSubscriptionRead, ServerSettingRead, ServerSettingsModify, SettingRead, diff --git a/src/server/bridges/AppBridges.ts b/src/server/bridges/AppBridges.ts index 2004251de..3ee1d3fa2 100644 --- a/src/server/bridges/AppBridges.ts +++ b/src/server/bridges/AppBridges.ts @@ -10,6 +10,7 @@ import { ILivechatBridge } from './ILivechatBridge'; import { IMessageBridge } from './IMessageBridge'; import { IPersistenceBridge } from './IPersistenceBridge'; import { IRoomBridge } from './IRoomBridge'; +import { IRoomSubscriptionBridge } from './IRoomSubscriptionBridge'; import { IServerSettingBridge } from './IServerSettingBridge'; import { IUiInteractionBridge } from './IUiInteractionBridge'; import { IUploadBridge } from './IUploadBridge'; @@ -27,6 +28,7 @@ export abstract class AppBridges { public abstract getPersistenceBridge(): IPersistenceBridge; public abstract getAppActivationBridge(): IAppActivationBridge; public abstract getRoomBridge(): IRoomBridge; + public abstract getRoomSubscriptionBridge(): IRoomSubscriptionBridge; public abstract getInternalBridge(): IInternalBridge; public abstract getServerSettingBridge(): IServerSettingBridge; public abstract getUploadBridge(): IUploadBridge; diff --git a/src/server/bridges/IRoomSubscriptionBridge.ts b/src/server/bridges/IRoomSubscriptionBridge.ts new file mode 100644 index 000000000..d27ae7b91 --- /dev/null +++ b/src/server/bridges/IRoomSubscriptionBridge.ts @@ -0,0 +1,7 @@ +import { IRoomSubscription } from '../../definition/subscriptions'; + +export interface IRoomSubscriptionBridge { + getByRoomId(roomId: string, appId: string): Promise>; + + getByUserId(userId: string, appId: string): Promise>; +} diff --git a/src/server/bridges/index.ts b/src/server/bridges/index.ts index 479f5a3fc..c46a5a26e 100644 --- a/src/server/bridges/index.ts +++ b/src/server/bridges/index.ts @@ -11,6 +11,7 @@ import { ILivechatBridge } from './ILivechatBridge'; import { IMessageBridge } from './IMessageBridge'; import { IPersistenceBridge } from './IPersistenceBridge'; import { IRoomBridge } from './IRoomBridge'; +import { IRoomSubscriptionBridge } from './IRoomSubscriptionBridge'; import { IServerSettingBridge } from './IServerSettingBridge'; import { IUiInteractionBridge } from './IUiInteractionBridge'; import { IUploadBridge } from './IUploadBridge'; @@ -29,6 +30,7 @@ export { IAppCommandBridge, IAppApiBridge, IRoomBridge, + IRoomSubscriptionBridge, IInternalBridge, IServerSettingBridge, IUserBridge, diff --git a/src/server/compiler/AppCompiler.ts b/src/server/compiler/AppCompiler.ts index 6ec7154f9..88f8f4dc3 100644 --- a/src/server/compiler/AppCompiler.ts +++ b/src/server/compiler/AppCompiler.ts @@ -36,6 +36,7 @@ export class AppCompiler { types: ['node'], // Set this to true if you would like to see the module resolution process traceResolution: false, + lib: ['lib.esnext.d.ts'], }; this.libraryFiles = {}; @@ -122,7 +123,7 @@ export class AppCompiler { return resolvedModules.push(rs.resolvedModule); } - console.log(`Failed to resolve module: ${ moduleName }`); + console.warn(`Failed to resolve module: ${ moduleName }`); } /** @@ -195,7 +196,7 @@ export class AppCompiler { if (moduleNames.length > resolvedModules.length) { const failedCount = moduleNames.length - resolvedModules.length; - console.log(`Failed to resolved ${ failedCount } modules for ${ info.name } v${ info.version }!`); + console.warn(`Failed to resolved ${ failedCount } modules for ${ info.name } v${ info.version }!`); } return resolvedModules; diff --git a/src/server/managers/AppAccessorManager.ts b/src/server/managers/AppAccessorManager.ts index 1d267ab47..99f710336 100644 --- a/src/server/managers/AppAccessorManager.ts +++ b/src/server/managers/AppAccessorManager.ts @@ -25,6 +25,7 @@ import { PersistenceRead, Reader, RoomRead, + RoomSubscriptionRead, ServerSettingRead, ServerSettingsModify, SettingRead, @@ -128,12 +129,13 @@ export class AppAccessorManager { const msg = new MessageRead(this.bridges.getMessageBridge(), appId); const persist = new PersistenceRead(this.bridges.getPersistenceBridge(), appId); const room = new RoomRead(this.bridges.getRoomBridge(), appId); + const subscr = new RoomSubscriptionRead(this.bridges.getRoomSubscriptionBridge(), appId); const user = new UserRead(this.bridges.getUserBridge(), appId); const noti = new Notifier(this.bridges.getUserBridge(), this.bridges.getMessageBridge(), appId); const livechat = new LivechatRead(this.bridges.getLivechatBridge(), appId); const upload = new UploadRead(this.bridges.getUploadBridge(), appId); - this.readers.set(appId, new Reader(env, msg, persist, room, user, noti, livechat, upload)); + this.readers.set(appId, new Reader(env, msg, persist, room, subscr, user, noti, livechat, upload)); } return this.readers.get(appId); diff --git a/tests/server/accessors/Reader.spec.ts b/tests/server/accessors/Reader.spec.ts index d51db7656..808b99070 100644 --- a/tests/server/accessors/Reader.spec.ts +++ b/tests/server/accessors/Reader.spec.ts @@ -1,5 +1,5 @@ import { Expect, SetupFixture, Test } from 'alsatian'; -import { IEnvironmentRead, ILivechatRead, IMessageRead, INotifier, IPersistenceRead, IRoomRead, IUploadRead, IUserRead } from '../../../src/definition/accessors'; +import { IEnvironmentRead, ILivechatRead, IMessageRead, INotifier, IPersistenceRead, IRoomRead, IRoomSubscriptionRead, IUploadRead, IUserRead } from '../../../src/definition/accessors'; import { Reader } from '../../../src/server/accessors'; @@ -8,6 +8,7 @@ export class ReaderAccessorTestFixture { private msg: IMessageRead; private pr: IPersistenceRead; private rm: IRoomRead; + private sb: IRoomSubscriptionRead; private ur: IUserRead; private ni: INotifier; private livechat: ILivechatRead; @@ -19,6 +20,7 @@ export class ReaderAccessorTestFixture { this.msg = {} as IMessageRead; this.pr = {} as IPersistenceRead; this.rm = {} as IRoomRead; + this.sb = {} as IRoomSubscriptionRead; this.ur = {} as IUserRead; this.ni = {} as INotifier; this.livechat = {} as ILivechatRead; @@ -27,14 +29,15 @@ export class ReaderAccessorTestFixture { @Test() public useReader() { - Expect(() => new Reader(this.env, this.msg, this.pr, this.rm, this.ur, this.ni, this.livechat, this.upload)).not.toThrow(); + Expect(() => new Reader(this.env, this.msg, this.pr, this.rm, this.sb, this.ur, this.ni, this.livechat, this.upload)).not.toThrow(); - const rd = new Reader(this.env, this.msg, this.pr, this.rm, this.ur, this.ni, this.livechat, this.upload); + const rd = new Reader(this.env, this.msg, this.pr, this.rm, this.sb, this.ur, this.ni, this.livechat, this.upload); Expect(rd.getEnvironmentReader()).toBeDefined(); Expect(rd.getMessageReader()).toBeDefined(); Expect(rd.getNotifier()).toBeDefined(); Expect(rd.getPersistenceReader()).toBeDefined(); Expect(rd.getRoomReader()).toBeDefined(); + Expect(rd.getRoomSubscriptionReader()).toBeDefined(); Expect(rd.getUserReader()).toBeDefined(); Expect(rd.getLivechatReader()).toBeDefined(); Expect(rd.getUploadReader()).toBeDefined(); diff --git a/tests/server/compiler/AppCompiler.spec.ts b/tests/server/compiler/AppCompiler.spec.ts index 7a5eb31e3..5663bd57d 100644 --- a/tests/server/compiler/AppCompiler.spec.ts +++ b/tests/server/compiler/AppCompiler.spec.ts @@ -23,6 +23,7 @@ export class AppCompilerTestFixture { emitDecoratorMetadata: true, experimentalDecorators: true, traceResolution: false, + lib: ['lib.esnext.d.ts'], }; Expect((compiler as any).compilerOptions).toEqual(expectedOptions); diff --git a/tests/test-data/bridges/appBridges.ts b/tests/test-data/bridges/appBridges.ts index ba3704b1e..1ab26785e 100644 --- a/tests/test-data/bridges/appBridges.ts +++ b/tests/test-data/bridges/appBridges.ts @@ -10,6 +10,7 @@ import { IMessageBridge, IPersistenceBridge, IRoomBridge, + IRoomSubscriptionBridge, IServerSettingBridge, IUiInteractionBridge, IUploadBridge, @@ -27,6 +28,7 @@ import { TestsMessageBridge } from './messageBridge'; import { TestsPersisBridge } from './persisBridge'; import { TestsRoomBridge } from './roomBridge'; import { TestsServerSettingBridge } from './serverSettingBridge'; +import { TestsSubscriptionBridge } from './subscriptionBridge'; import { TestsUiIntegrationBridge } from './uiIntegrationBridge'; import { TestUploadBridge } from './uploadBridge'; import { TestsUserBridge } from './userBridge'; @@ -41,6 +43,7 @@ export class TestsAppBridges extends AppBridges { private readonly msgBridge: TestsMessageBridge; private readonly persisBridge: TestsPersisBridge; private readonly roomBridge: TestsRoomBridge; + private readonly subscriptionBridge: TestsSubscriptionBridge; private readonly internalBridge: TestsInternalBridge; private readonly userBridge: TestsUserBridge; private readonly httpBridge: TestsHttpBridge; @@ -59,6 +62,7 @@ export class TestsAppBridges extends AppBridges { this.msgBridge = new TestsMessageBridge(); this.persisBridge = new TestsPersisBridge(); this.roomBridge = new TestsRoomBridge(); + this.subscriptionBridge = new TestsSubscriptionBridge(); this.internalBridge = new TestsInternalBridge(); this.userBridge = new TestsUserBridge(); this.httpBridge = new TestsHttpBridge(); @@ -111,6 +115,10 @@ export class TestsAppBridges extends AppBridges { return this.roomBridge; } + public getRoomSubscriptionBridge(): IRoomSubscriptionBridge { + return this.subscriptionBridge; + } + public getInternalBridge(): IInternalBridge { return this.internalBridge; } diff --git a/tests/test-data/bridges/subscriptionBridge.ts b/tests/test-data/bridges/subscriptionBridge.ts new file mode 100644 index 000000000..49cac56fb --- /dev/null +++ b/tests/test-data/bridges/subscriptionBridge.ts @@ -0,0 +1,12 @@ +import { IRoomSubscription } from '../../../src/definition/subscriptions'; +import { IRoomSubscriptionBridge } from '../../../src/server/bridges'; + +export class TestsSubscriptionBridge implements IRoomSubscriptionBridge { + public getByRoomId(roomId: string, appId: string): Promise> { + throw new Error('Method not implemented.'); + } + + public getByUserId(userId: string, appId: string): Promise> { + throw new Error('Method not implemented.'); + } +} diff --git a/tsconfig.json b/tsconfig.json index b2266c9b5..ca1d4a9af 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "experimentalDecorators": true, "moduleResolution": "node", "types": ["node"], - "lib": ["es2017", "dom"], + "lib": ["es2018", "dom"], "outDir": "." }, "exclude": [