Skip to content

Commit

Permalink
Add an action to search for users in the user directory according to …
Browse files Browse the repository at this point in the history
…MSC3973 (#79)

Signed-off-by: Dominik Henneke <[email protected]>
  • Loading branch information
dhenneke authored Mar 17, 2023
1 parent 839d5c2 commit 9e2acc8
Show file tree
Hide file tree
Showing 9 changed files with 442 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/ClientWidgetApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ import {
IReadRelationsFromWidgetActionRequest,
IReadRelationsFromWidgetResponseData,
} from "./interfaces/ReadRelationsAction";
import {
IUserDirectorySearchFromWidgetActionRequest,
IUserDirectorySearchFromWidgetResponseData,
} from "./interfaces/UserDirectorySearchAction";

/**
* API handler for the client side of widgets. This raises events
Expand Down Expand Up @@ -619,6 +623,49 @@ export class ClientWidgetApi extends EventEmitter {
}
}

private async handleUserDirectorySearch(request: IUserDirectorySearchFromWidgetActionRequest) {
if (!this.hasCapability(MatrixCapabilities.MSC3973UserDirectorySearch)) {
return this.transport.reply<IWidgetApiErrorResponseData>(request, {
error: { message: "Missing capability" },
});
}

if (typeof request.data.search_term !== 'string') {
return this.transport.reply<IWidgetApiErrorResponseData>(request, {
error: { message: "Invalid request - missing search term" },
});
}

if (request.data.limit !== undefined && request.data.limit < 0) {
return this.transport.reply<IWidgetApiErrorResponseData>(request, {
error: { message: "Invalid request - limit out of range" },
});
}

try {
const result = await this.driver.searchUserDirectory(
request.data.search_term, request.data.limit,
);

return this.transport.reply<IUserDirectorySearchFromWidgetResponseData>(
request,
{
limited: result.limited,
results: result.results.map(r => ({
user_id: r.userId,
display_name: r.displayName,
avatar_url: r.avatarUrl,
})),
},
);
} catch (e) {
console.error("error searching in the user directory", e);
await this.transport.reply<IWidgetApiErrorResponseData>(request, {
error: { message: "Unexpected error while searching in the user directory" },
});
}
}

private handleMessage(ev: CustomEvent<IWidgetApiRequest>) {
if (this.isStopped) return;
const actionEv = new CustomEvent(`action:${ev.detail.action}`, {
Expand Down Expand Up @@ -650,6 +697,8 @@ export class ClientWidgetApi extends EventEmitter {
return this.handleUnwatchTurnServers(<IUnwatchTurnServersRequest>ev.detail);
case WidgetApiFromWidgetAction.MSC3869ReadRelations:
return this.handleReadRelations(<IReadRelationsFromWidgetActionRequest>ev.detail);
case WidgetApiFromWidgetAction.MSC3973UserDirectorySearch:
return this.handleUserDirectorySearch(<IUserDirectorySearchFromWidgetActionRequest>ev.detail)
default:
return this.transport.reply(ev.detail, <IWidgetApiErrorResponseData>{
error: {
Expand Down
30 changes: 30 additions & 0 deletions src/WidgetApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ import {
IReadRelationsFromWidgetRequestData,
IReadRelationsFromWidgetResponseData,
} from "./interfaces/ReadRelationsAction";
import {
IUserDirectorySearchFromWidgetRequestData,
IUserDirectorySearchFromWidgetResponseData,
} from "./interfaces/UserDirectorySearchAction";

/**
* API handler for widgets. This raises events for each action
Expand Down Expand Up @@ -592,6 +596,32 @@ export class WidgetApi extends EventEmitter {
}
}

/**
* Search for users in the user directory.
* @param searchTerm The term to search for.
* @param limit The maximum number of results to return. If not supplied, the
* @returns Resolves to the search results.
*/
public async searchUserDirectory(
searchTerm: string,
limit?: number,
): Promise<IUserDirectorySearchFromWidgetResponseData> {
const versions = await this.getClientVersions();
if (!versions.includes(UnstableApiVersion.MSC3973)) {
throw new Error("The user_directory_search action is not supported by the client.")
}

const data: IUserDirectorySearchFromWidgetRequestData = {
search_term: searchTerm,
limit,
};

return this.transport.send<
IUserDirectorySearchFromWidgetRequestData,
IUserDirectorySearchFromWidgetResponseData
>(WidgetApiFromWidgetAction.MSC3973UserDirectorySearch, data);
}

/**
* Starts the communication channel. This should be done early to ensure
* that messages are not missed. Communication can only be stopped by the client.
Expand Down
22 changes: 22 additions & 0 deletions src/driver/WidgetDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ export interface IReadEventRelationsResult {
prevBatch?: string;
}

export interface ISearchUserDirectoryResult {
limited: boolean;
results: Array<{
userId: string;
displayName?: string;
avatarUrl?: string;
}>;
}

/**
* Represents the functions and behaviour the widget-api is unable to
* do, such as prompting the user for information or interacting with
Expand Down Expand Up @@ -222,4 +231,17 @@ export abstract class WidgetDriver {
public getTurnServers(): AsyncGenerator<ITurnServer> {
throw new Error("TURN server support is not implemented");
}

/**
* Search for users in the user directory.
* @param searchTerm The term to search for.
* @param limit The maximum number of results to return. If not supplied, the
* @returns Resolves to the search results.
*/
public searchUserDirectory(
searchTerm: string,
limit?: number,
): Promise<ISearchUserDirectoryResult> {
return Promise.resolve({ limited: false, results: [] });
}
}
2 changes: 2 additions & 0 deletions src/interfaces/ApiVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export enum UnstableApiVersion {
MSC3819 = "org.matrix.msc3819",
MSC3846 = "town.robin.msc3846",
MSC3869 = "org.matrix.msc3869",
MSC3973 = "org.matrix.msc3973",
}

export type ApiVersion = MatrixApiVersion | UnstableApiVersion | string;
Expand All @@ -45,4 +46,5 @@ export const CurrentApiVersions: ApiVersion[] = [
UnstableApiVersion.MSC3819,
UnstableApiVersion.MSC3846,
UnstableApiVersion.MSC3869,
UnstableApiVersion.MSC3973,
];
4 changes: 4 additions & 0 deletions src/interfaces/Capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export enum MatrixCapabilities {
*/
MSC2931Navigate = "org.matrix.msc2931.navigate",
MSC3846TurnServers = "town.robin.msc3846.turn_servers",
/**
* @deprecated It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
}

export type Capability = MatrixCapabilities | string;
Expand Down
42 changes: 42 additions & 0 deletions src/interfaces/UserDirectorySearchAction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023 Nordeck IT + Consulting GmbH.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { IWidgetApiRequest, IWidgetApiRequestData } from "./IWidgetApiRequest";
import { IWidgetApiResponseData } from "./IWidgetApiResponse";
import { WidgetApiFromWidgetAction } from "./WidgetApiAction";

export interface IUserDirectorySearchFromWidgetRequestData extends IWidgetApiRequestData {
search_term: string; // eslint-disable-line camelcase
limit?: number;
}

export interface IUserDirectorySearchFromWidgetActionRequest extends IWidgetApiRequest {
action: WidgetApiFromWidgetAction.MSC3973UserDirectorySearch;
data: IUserDirectorySearchFromWidgetRequestData;
}

export interface IUserDirectorySearchFromWidgetResponseData extends IWidgetApiResponseData {
limited: boolean;
results: Array<{
user_id: string; // eslint-disable-line camelcase
display_name?: string; // eslint-disable-line camelcase
avatar_url?: string; // eslint-disable-line camelcase
}>;
}

export interface IUserDirectorySearchFromWidgetActionResponse extends IUserDirectorySearchFromWidgetActionRequest {
response: IUserDirectorySearchFromWidgetResponseData;
}
5 changes: 5 additions & 0 deletions src/interfaces/WidgetApiAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ export enum WidgetApiFromWidgetAction {
* @deprecated It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3869ReadRelations = "org.matrix.msc3869.read_relations",

/**
* @deprecated It is not recommended to rely on this existing - it can be removed without notice.
*/
MSC3973UserDirectorySearch = "org.matrix.msc3973.user_directory_search",
}

export type WidgetApiAction = WidgetApiToWidgetAction | WidgetApiFromWidgetAction | string;
Loading

0 comments on commit 9e2acc8

Please sign in to comment.