From df008c419bdd1b906d2dd5164d8f229d4b439c7e Mon Sep 17 00:00:00 2001 From: Guilherme Gazzo Date: Wed, 7 Jun 2023 13:57:08 -0300 Subject: [PATCH] Extend typing capability for threads --- src/definition/accessors/INotifier.ts | 40 ++++++++++++++++++---- src/server/accessors/Notifier.ts | 25 ++++++-------- src/server/bridges/MessageBridge.ts | 43 +++++++++++++++++------- tests/test-data/bridges/messageBridge.ts | 4 +-- 4 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/definition/accessors/INotifier.ts b/src/definition/accessors/INotifier.ts index 7610d56eb..2ab111b8c 100644 --- a/src/definition/accessors/INotifier.ts +++ b/src/definition/accessors/INotifier.ts @@ -3,22 +3,48 @@ import { IRoom } from '../rooms'; import { IUser } from '../users'; import { IMessageBuilder } from './IMessageBuilder'; -export enum TypingScope { - Room = 'room', +export interface ITypingRoomOptions { + /** + * The typing scope where the typing message should be presented, + * TypingScope.Room by default. + */ + scope?: 'room'; + /** + * The id of the typing scope + * + * TypingScope.Room <-> room.id + */ + id: string; + /** + * The name of the user who is typing the message + * + * **Note**: If not provided, it will use app assigned + * user's name by default. + */ + username?: string; } -export interface ITypingOptions { +export interface ITypingThreadOptions { /** * The typing scope where the typing message should be presented, * TypingScope.Room by default. */ - scope?: TypingScope; + scope: 'thread'; /** * The id of the typing scope * * TypingScope.Room <-> room.id */ - id: string; + roomId: string; + + /** + * The id of the thread + * + * TypingScope.Thread <-> thread.id + * + */ + + threadId: string; /** * The name of the user who is typing the message * @@ -28,6 +54,8 @@ export interface ITypingOptions { username?: string; } +export type TypingThreadOptions = ITypingThreadOptions | ITypingRoomOptions; + export interface INotifier { /** * Notifies the provided user of the provided message. @@ -56,7 +84,7 @@ export interface INotifier { * * @returns a cancellation function to stop typing */ - typing(options: ITypingOptions): Promise<() => Promise>; + typing(options: ITypingRoomOptions): Promise<() => Promise>; /** Gets a new message builder for building a notification message. */ getMessageBuilder(): IMessageBuilder; diff --git a/src/server/accessors/Notifier.ts b/src/server/accessors/Notifier.ts index 98a3ec98a..0737932df 100644 --- a/src/server/accessors/Notifier.ts +++ b/src/server/accessors/Notifier.ts @@ -1,5 +1,5 @@ import { IMessageBuilder, INotifier } from '../../definition/accessors'; -import { ITypingOptions, TypingScope } from '../../definition/accessors/INotifier'; +import { TypingThreadOptions } from '../../definition/accessors/INotifier'; import { IMessage } from '../../definition/messages'; import { IRoom } from '../../definition/rooms'; import { IUser } from '../../definition/users'; @@ -7,11 +7,7 @@ import { MessageBridge, UserBridge } from '../bridges'; import { MessageBuilder } from './MessageBuilder'; export class Notifier implements INotifier { - constructor( - private readonly userBridge: UserBridge, - private readonly msgBridge: MessageBridge, - private readonly appId: string, - ) { } + constructor(private readonly userBridge: UserBridge, private readonly msgBridge: MessageBridge, private readonly appId: string) {} public async notifyUser(user: IUser, message: IMessage): Promise { if (!message.sender || !message.sender.id) { @@ -33,17 +29,16 @@ export class Notifier implements INotifier { await this.msgBridge.doNotifyRoom(room, message, this.appId); } - public async typing(options: ITypingOptions): Promise<() => Promise> { - options.scope = options.scope || TypingScope.Room; + public async typing(options: TypingThreadOptions): Promise<() => Promise> { + const payload = { + scope: 'room' as const, + ...options, + username: options.username ?? (await this.userBridge.doGetAppUser(this.appId).then((u) => u.name ?? '')), + }; - if (!options.username) { - const appUser = await this.userBridge.doGetAppUser(this.appId); - options.username = appUser && appUser.name || ''; - } - - this.msgBridge.doTyping({ ...options, isTyping: true }, this.appId); + this.msgBridge.doTyping({ ...payload, isTyping: true }, this.appId); - return () => this.msgBridge.doTyping({ ...options, isTyping: false }, this.appId); + return () => this.msgBridge.doTyping({ ...payload, isTyping: false }, this.appId); } public getMessageBuilder(): IMessageBuilder { diff --git a/src/server/bridges/MessageBridge.ts b/src/server/bridges/MessageBridge.ts index 1ca957fab..344fe15ea 100644 --- a/src/server/bridges/MessageBridge.ts +++ b/src/server/bridges/MessageBridge.ts @@ -1,4 +1,4 @@ -import { ITypingOptions } from '../../definition/accessors/INotifier'; +import { ITypingRoomOptions, ITypingThreadOptions } from '../../definition/accessors/INotifier'; import { IMessage } from '../../definition/messages'; import { IRoom } from '../../definition/rooms'; import { IUser } from '../../definition/users'; @@ -7,10 +7,25 @@ import { AppPermissionManager } from '../managers/AppPermissionManager'; import { AppPermissions } from '../permissions/AppPermissions'; import { BaseBridge } from './BaseBridge'; -export interface ITypingDescriptor extends ITypingOptions { +/** @deprecated use TypingDescriptor instead */ +export interface ITypingDescriptor extends ITypingRoomOptions { isTyping: boolean; } +type WithRequiredProperty = Type & { + [Property in Key]-?: Type[Property]; +}; + +type Pretty = { + [P in keyof K]: K[P]; +}; + +export type TypingDescriptor = Pretty< + WithRequiredProperty & { + isTyping: boolean; + } +>; + export abstract class MessageBridge extends BaseBridge { public async doCreate(message: IMessage, appId: string): Promise { if (this.hasWritePermission(appId)) { @@ -36,7 +51,7 @@ export abstract class MessageBridge extends BaseBridge { } } - public async doTyping(options: ITypingDescriptor, appId: string): Promise { + public async doTyping(options: TypingDescriptor, appId: string): Promise { if (this.hasWritePermission(appId)) { return this.typing(options, appId); } @@ -58,7 +73,7 @@ export abstract class MessageBridge extends BaseBridge { protected abstract update(message: IMessage, appId: string): Promise; protected abstract notifyUser(user: IUser, message: IMessage, appId: string): Promise; protected abstract notifyRoom(room: IRoom, message: IMessage, appId: string): Promise; - protected abstract typing(options: ITypingDescriptor, appId: string): Promise; + protected abstract typing(options: TypingDescriptor, appId: string): Promise; protected abstract getById(messageId: string, appId: string): Promise; protected abstract delete(message: IMessage, user: IUser, appId: string): Promise; @@ -67,10 +82,12 @@ export abstract class MessageBridge extends BaseBridge { return true; } - AppPermissionManager.notifyAboutError(new PermissionDeniedError({ - appId, - missingPermissions: [AppPermissions.message.read], - })); + AppPermissionManager.notifyAboutError( + new PermissionDeniedError({ + appId, + missingPermissions: [AppPermissions.message.read], + }), + ); return false; } @@ -80,10 +97,12 @@ export abstract class MessageBridge extends BaseBridge { return true; } - AppPermissionManager.notifyAboutError(new PermissionDeniedError({ - appId, - missingPermissions: [AppPermissions.message.write], - })); + AppPermissionManager.notifyAboutError( + new PermissionDeniedError({ + appId, + missingPermissions: [AppPermissions.message.write], + }), + ); return false; } diff --git a/tests/test-data/bridges/messageBridge.ts b/tests/test-data/bridges/messageBridge.ts index ba78f16cc..cd98be01f 100644 --- a/tests/test-data/bridges/messageBridge.ts +++ b/tests/test-data/bridges/messageBridge.ts @@ -2,7 +2,7 @@ import { IMessage } from '../../../src/definition/messages'; import { IRoom } from '../../../src/definition/rooms'; import { IUser } from '../../../src/definition/users'; import { MessageBridge } from '../../../src/server/bridges'; -import { ITypingDescriptor } from '../../../src/server/bridges/MessageBridge'; +import { TypingDescriptor } from '../../../src/server/bridges/MessageBridge'; export class TestsMessageBridge extends MessageBridge { public create(message: IMessage, appId: string): Promise { @@ -29,7 +29,7 @@ export class TestsMessageBridge extends MessageBridge { throw new Error('Method not implemented.'); } - public typing(options: ITypingDescriptor): Promise { + public typing(options: TypingDescriptor): Promise { throw new Error('Method not implemented.'); } }