Remove dead & duplicated code (#11405)
* Remove dead code * Make dead code happier * DRY pickle additional data calculation * Iterate
This commit is contained in:
parent
672ad98ec7
commit
27d79458da
25 changed files with 50 additions and 201 deletions
|
@ -281,16 +281,15 @@ export default class AddThreepid {
|
||||||
): Promise<[success?: boolean, result?: IAuthData | Error | null] | undefined> {
|
): Promise<[success?: boolean, result?: IAuthData | Error | null] | undefined> {
|
||||||
const authClient = new IdentityAuthClient();
|
const authClient = new IdentityAuthClient();
|
||||||
|
|
||||||
let result: { success: boolean } | MatrixError;
|
|
||||||
if (this.submitUrl) {
|
if (this.submitUrl) {
|
||||||
result = await this.matrixClient.submitMsisdnTokenOtherUrl(
|
await this.matrixClient.submitMsisdnTokenOtherUrl(
|
||||||
this.submitUrl,
|
this.submitUrl,
|
||||||
this.sessionId!,
|
this.sessionId!,
|
||||||
this.clientSecret,
|
this.clientSecret,
|
||||||
msisdnToken,
|
msisdnToken,
|
||||||
);
|
);
|
||||||
} else if (this.bind) {
|
} else if (this.bind) {
|
||||||
result = await this.matrixClient.submitMsisdnToken(
|
await this.matrixClient.submitMsisdnToken(
|
||||||
this.sessionId!,
|
this.sessionId!,
|
||||||
this.clientSecret,
|
this.clientSecret,
|
||||||
msisdnToken,
|
msisdnToken,
|
||||||
|
@ -299,9 +298,6 @@ export default class AddThreepid {
|
||||||
} else {
|
} else {
|
||||||
throw new UserFriendlyError("The add / bind with MSISDN flow is misconfigured");
|
throw new UserFriendlyError("The add / bind with MSISDN flow is misconfigured");
|
||||||
}
|
}
|
||||||
if (result instanceof Error) {
|
|
||||||
throw result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.bind) {
|
if (this.bind) {
|
||||||
await this.matrixClient.bindThreePid({
|
await this.matrixClient.bindThreePid({
|
||||||
|
|
|
@ -67,7 +67,7 @@ export default abstract class BasePlatform {
|
||||||
protected notificationCount = 0;
|
protected notificationCount = 0;
|
||||||
protected errorDidOccur = false;
|
protected errorDidOccur = false;
|
||||||
|
|
||||||
public constructor() {
|
protected constructor() {
|
||||||
dis.register(this.onAction);
|
dis.register(this.onAction);
|
||||||
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
this.startUpdateCheck = this.startUpdateCheck.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -365,14 +365,7 @@ export default abstract class BasePlatform {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const additionalData = new Uint8Array(userId.length + deviceId.length + 1);
|
const additionalData = this.getPickleAdditionalData(userId, deviceId);
|
||||||
for (let i = 0; i < userId.length; i++) {
|
|
||||||
additionalData[i] = userId.charCodeAt(i);
|
|
||||||
}
|
|
||||||
additionalData[userId.length] = 124; // "|"
|
|
||||||
for (let i = 0; i < deviceId.length; i++) {
|
|
||||||
additionalData[userId.length + 1 + i] = deviceId.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const key = await crypto.subtle.decrypt(
|
const key = await crypto.subtle.decrypt(
|
||||||
|
@ -387,6 +380,18 @@ export default abstract class BasePlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getPickleAdditionalData(userId: string, deviceId: string): Uint8Array {
|
||||||
|
const additionalData = new Uint8Array(userId.length + deviceId.length + 1);
|
||||||
|
for (let i = 0; i < userId.length; i++) {
|
||||||
|
additionalData[i] = userId.charCodeAt(i);
|
||||||
|
}
|
||||||
|
additionalData[userId.length] = 124; // "|"
|
||||||
|
for (let i = 0; i < deviceId.length; i++) {
|
||||||
|
additionalData[userId.length + 1 + i] = deviceId.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return additionalData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and store a pickle key for encrypting libolm objects.
|
* Create and store a pickle key for encrypting libolm objects.
|
||||||
* @param {string} userId the user ID for the user that the pickle key is for.
|
* @param {string} userId the user ID for the user that the pickle key is for.
|
||||||
|
@ -408,15 +413,7 @@ export default abstract class BasePlatform {
|
||||||
const iv = new Uint8Array(32);
|
const iv = new Uint8Array(32);
|
||||||
crypto.getRandomValues(iv);
|
crypto.getRandomValues(iv);
|
||||||
|
|
||||||
const additionalData = new Uint8Array(userId.length + deviceId.length + 1);
|
const additionalData = this.getPickleAdditionalData(userId, deviceId);
|
||||||
for (let i = 0; i < userId.length; i++) {
|
|
||||||
additionalData[i] = userId.charCodeAt(i);
|
|
||||||
}
|
|
||||||
additionalData[userId.length] = 124; // "|"
|
|
||||||
for (let i = 0; i < deviceId.length; i++) {
|
|
||||||
additionalData[userId.length + 1 + i] = deviceId.charCodeAt(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData }, cryptoKey, randomArray);
|
const encrypted = await crypto.subtle.encrypt({ name: "AES-GCM", iv, additionalData }, cryptoKey, randomArray);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -75,10 +75,6 @@ export default class IdentityAuthClient {
|
||||||
return window.localStorage.getItem("mx_is_access_token");
|
return window.localStorage.getItem("mx_is_access_token");
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasCredentials(): boolean {
|
|
||||||
return Boolean(this.accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a promise that resolves to the access_token string from the IS
|
// Returns a promise that resolves to the access_token string from the IS
|
||||||
public async getAccessToken({ check = true } = {}): Promise<string | null> {
|
public async getAccessToken({ check = true } = {}): Promise<string | null> {
|
||||||
if (!this.authEnabled) {
|
if (!this.authEnabled) {
|
||||||
|
|
|
@ -429,15 +429,6 @@ export default class LegacyCallHandler extends EventEmitter {
|
||||||
return this.calls.get(roomId) || null;
|
return this.calls.get(roomId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAnyActiveCall(): MatrixCall | null {
|
|
||||||
for (const call of this.calls.values()) {
|
|
||||||
if (call.state !== CallState.Ended) {
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getAllActiveCalls(): MatrixCall[] {
|
public getAllActiveCalls(): MatrixCall[] {
|
||||||
const activeCalls: MatrixCall[] = [];
|
const activeCalls: MatrixCall[] = [];
|
||||||
|
|
||||||
|
|
|
@ -47,41 +47,6 @@ export default class PasswordReset {
|
||||||
this.clientSecret = this.client.generateClientSecret();
|
this.clientSecret = this.client.generateClientSecret();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to reset the user's password. This will trigger a side-effect of
|
|
||||||
* sending an email to the provided email address.
|
|
||||||
* @param {string} emailAddress The email address
|
|
||||||
* @param {string} newPassword The new password for the account.
|
|
||||||
* @param {boolean} logoutDevices Should all devices be signed out after the reset? Defaults to `true`.
|
|
||||||
* @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
|
||||||
*/
|
|
||||||
public async resetPassword(
|
|
||||||
emailAddress: string,
|
|
||||||
newPassword: string,
|
|
||||||
logoutDevices = true,
|
|
||||||
): Promise<IRequestTokenResponse> {
|
|
||||||
this.password = newPassword;
|
|
||||||
this.logoutDevices = logoutDevices;
|
|
||||||
this.sendAttempt++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await this.client.requestPasswordEmailToken(
|
|
||||||
emailAddress,
|
|
||||||
this.clientSecret,
|
|
||||||
this.sendAttempt,
|
|
||||||
);
|
|
||||||
this.sessionId = result.sid;
|
|
||||||
return result;
|
|
||||||
} catch (err: any) {
|
|
||||||
if (err.errcode === "M_THREEPID_NOT_FOUND") {
|
|
||||||
err.message = _t("This email address was not found");
|
|
||||||
} else if (err.httpStatus) {
|
|
||||||
err.message = err.message + ` (Status ${err.httpStatus})`;
|
|
||||||
}
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request a password reset token.
|
* Request a password reset token.
|
||||||
* This will trigger a side-effect of sending an email to the provided email address.
|
* This will trigger a side-effect of sending an email to the provided email address.
|
||||||
|
|
|
@ -256,9 +256,8 @@ export function determineUnreadState(
|
||||||
return { symbol: null, count: trueCount, color: NotificationColor.Grey };
|
return { symbol: null, count: trueCount, color: NotificationColor.Grey };
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have any notified messages, but we might have unread messages. Let's
|
// We don't have any notified messages, but we might have unread messages. Let's find out.
|
||||||
// find out.
|
let hasUnread: boolean;
|
||||||
let hasUnread = false;
|
|
||||||
if (threadId) hasUnread = doesRoomOrThreadHaveUnreadMessages(room.getThread(threadId)!);
|
if (threadId) hasUnread = doesRoomOrThreadHaveUnreadMessages(room.getThread(threadId)!);
|
||||||
else hasUnread = doesRoomHaveUnreadMessages(room);
|
else hasUnread = doesRoomHaveUnreadMessages(room);
|
||||||
|
|
||||||
|
|
|
@ -679,7 +679,7 @@ function canSendEvent(event: MessageEvent<any>, roomId: string): void {
|
||||||
}
|
}
|
||||||
const me = client.credentials.userId!;
|
const me = client.credentials.userId!;
|
||||||
|
|
||||||
let canSend = false;
|
let canSend: boolean;
|
||||||
if (isState) {
|
if (isState) {
|
||||||
canSend = room.currentState.maySendStateEvent(evType, me);
|
canSend = room.currentState.maySendStateEvent(evType, me);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -117,7 +117,7 @@ const FeedbackDialog: React.FC<IProps> = (props: IProps) => {
|
||||||
return (
|
return (
|
||||||
<QuestionDialog
|
<QuestionDialog
|
||||||
className="mx_FeedbackDialog"
|
className="mx_FeedbackDialog"
|
||||||
hasCancelButton={!!hasFeedback}
|
hasCancelButton={hasFeedback}
|
||||||
title={_t("Feedback")}
|
title={_t("Feedback")}
|
||||||
description={
|
description={
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
|
|
@ -461,7 +461,7 @@ export default class EditorModel {
|
||||||
*/
|
*/
|
||||||
public transform(callback: ManualTransformCallback): Promise<void> {
|
public transform(callback: ManualTransformCallback): Promise<void> {
|
||||||
const pos = callback();
|
const pos = callback();
|
||||||
let acPromise: Promise<void> | null = null;
|
let acPromise: Promise<void> | null;
|
||||||
if (!(pos instanceof Range)) {
|
if (!(pos instanceof Range)) {
|
||||||
acPromise = this.setActivePart(pos, true);
|
acPromise = this.setActivePart(pos, true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -112,13 +112,6 @@ export default abstract class BaseEventIndexManager {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if our event index is empty.
|
|
||||||
*/
|
|
||||||
public indexIsEmpty(): Promise<boolean> {
|
|
||||||
throw new Error("Unimplemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the room with the given id is already indexed.
|
* Check if the room with the given id is already indexed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -26,7 +26,6 @@ import IntegrationsImpossibleDialog from "../components/views/dialogs/Integratio
|
||||||
import IntegrationsDisabledDialog from "../components/views/dialogs/IntegrationsDisabledDialog";
|
import IntegrationsDisabledDialog from "../components/views/dialogs/IntegrationsDisabledDialog";
|
||||||
import WidgetUtils from "../utils/WidgetUtils";
|
import WidgetUtils from "../utils/WidgetUtils";
|
||||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||||
import { parseUrl } from "../utils/UrlUtils";
|
|
||||||
|
|
||||||
const KIND_PREFERENCE = [
|
const KIND_PREFERENCE = [
|
||||||
// Ordered: first is most preferred, last is least preferred.
|
// Ordered: first is most preferred, last is least preferred.
|
||||||
|
@ -179,52 +178,6 @@ export class IntegrationManagers {
|
||||||
public showDisabledDialog(): void {
|
public showDisabledDialog(): void {
|
||||||
Modal.createDialog(IntegrationsDisabledDialog);
|
Modal.createDialog(IntegrationsDisabledDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to discover an integration manager using only its name. This will not validate that
|
|
||||||
* the integration manager is functional - that is the caller's responsibility.
|
|
||||||
* @param {string} domainName The domain name to look up.
|
|
||||||
* @returns {Promise<IntegrationManagerInstance>} Resolves to an integration manager instance,
|
|
||||||
* or null if none was found.
|
|
||||||
*/
|
|
||||||
public async tryDiscoverManager(domainName: string): Promise<IntegrationManagerInstance | null> {
|
|
||||||
logger.log("Looking up integration manager via .well-known");
|
|
||||||
if (domainName.startsWith("http:") || domainName.startsWith("https:")) {
|
|
||||||
// trim off the scheme and just use the domain
|
|
||||||
domainName = parseUrl(domainName).host;
|
|
||||||
}
|
|
||||||
|
|
||||||
let wkConfig: IClientWellKnown;
|
|
||||||
try {
|
|
||||||
const result = await fetch(`https://${domainName}/.well-known/matrix/integrations`);
|
|
||||||
wkConfig = await result.json();
|
|
||||||
} catch (e) {
|
|
||||||
logger.error(e);
|
|
||||||
logger.warn("Failed to locate integration manager");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!wkConfig || !wkConfig["m.integrations_widget"]) {
|
|
||||||
logger.warn("Missing integrations widget on .well-known response");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const widget = wkConfig["m.integrations_widget"];
|
|
||||||
if (!widget["url"] || !widget["data"] || !widget["data"]["api_url"]) {
|
|
||||||
logger.warn("Malformed .well-known response for integrations widget");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All discovered managers are per-user managers
|
|
||||||
const manager = new IntegrationManagerInstance(Kind.Account, widget["data"]["api_url"], widget["url"]);
|
|
||||||
logger.log("Got an integration manager (untested)");
|
|
||||||
|
|
||||||
// We don't test the manager because the caller may need to do extra
|
|
||||||
// checks or similar with it. For instance, they may need to deal with
|
|
||||||
// terms of service or want to call something particular.
|
|
||||||
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debugging
|
// For debugging
|
||||||
|
|
|
@ -63,10 +63,6 @@ export class BanList {
|
||||||
return this._rules.filter((r) => r.kind === RULE_USER);
|
return this._rules.filter((r) => r.kind === RULE_USER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get roomRules(): ListRule[] {
|
|
||||||
return this._rules.filter((r) => r.kind === RULE_ROOM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async banEntity(kind: string, entity: string, reason: string): Promise<any> {
|
public async banEntity(kind: string, entity: string, reason: string): Promise<any> {
|
||||||
const type = ruleTypeToStable(kind);
|
const type = ruleTypeToStable(kind);
|
||||||
if (!type) return; // unknown rule type
|
if (!type) return; // unknown rule type
|
||||||
|
|
|
@ -157,7 +157,7 @@ export abstract class Call extends TypedEventEmitter<CallEvent, CallEventHandler
|
||||||
this.emit(CallEvent.Participants, value, prevValue);
|
this.emit(CallEvent.Participants, value, prevValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(
|
protected constructor(
|
||||||
/**
|
/**
|
||||||
* The widget used to access this call.
|
* The widget used to access this call.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -117,7 +117,7 @@ async function collectBugReport(opts: IOpts = {}, gzipLogs = true): Promise<Form
|
||||||
);
|
);
|
||||||
|
|
||||||
body.append("secret_storage_ready", String(await client.isSecretStorageReady()));
|
body.append("secret_storage_ready", String(await client.isSecretStorageReady()));
|
||||||
body.append("secret_storage_key_in_account", String(!!(await secretStorage.hasKey())));
|
body.append("secret_storage_key_in_account", String(await secretStorage.hasKey()));
|
||||||
|
|
||||||
body.append("session_backup_key_in_secret_storage", String(!!(await client.isKeyBackupKeyStored())));
|
body.append("session_backup_key_in_secret_storage", String(!!(await client.isKeyBackupKeyStored())));
|
||||||
const sessionBackupKeyFromCache = await client.crypto.getSessionBackupPrivateKey();
|
const sessionBackupKeyFromCache = await client.crypto.getSessionBackupPrivateKey();
|
||||||
|
|
|
@ -139,7 +139,7 @@ async function getCryptoContext(client: MatrixClient): Promise<CryptoContext> {
|
||||||
!!(pkCache && (await pkCache.getCrossSigningKeyCache?.("user_signing"))),
|
!!(pkCache && (await pkCache.getCrossSigningKeyCache?.("user_signing"))),
|
||||||
),
|
),
|
||||||
secret_storage_ready: String(await client.isSecretStorageReady()),
|
secret_storage_ready: String(await client.isSecretStorageReady()),
|
||||||
secret_storage_key_in_account: String(!!(await secretStorage.hasKey())),
|
secret_storage_key_in_account: String(await secretStorage.hasKey()),
|
||||||
session_backup_key_in_secret_storage: String(!!(await client.isKeyBackupKeyStored())),
|
session_backup_key_in_secret_storage: String(!!(await client.isKeyBackupKeyStored())),
|
||||||
session_backup_key_cached: String(!!sessionBackupKeyFromCache),
|
session_backup_key_cached: String(!!sessionBackupKeyFromCache),
|
||||||
session_backup_key_well_formed: String(sessionBackupKeyFromCache instanceof Uint8Array),
|
session_backup_key_well_formed: String(sessionBackupKeyFromCache instanceof Uint8Array),
|
||||||
|
|
|
@ -577,10 +577,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
|
||||||
* @param {IFilterCondition} filter The filter condition to add.
|
* @param {IFilterCondition} filter The filter condition to add.
|
||||||
*/
|
*/
|
||||||
public async addFilter(filter: IFilterCondition): Promise<void> {
|
public async addFilter(filter: IFilterCondition): Promise<void> {
|
||||||
let promise = Promise.resolve();
|
|
||||||
filter.on(FILTER_CHANGED, this.onPrefilterUpdated);
|
filter.on(FILTER_CHANGED, this.onPrefilterUpdated);
|
||||||
this.prefilterConditions.push(filter);
|
this.prefilterConditions.push(filter);
|
||||||
promise = this.recalculatePrefiltering();
|
const promise = this.recalculatePrefiltering();
|
||||||
promise.then(() => this.updateFn.trigger());
|
promise.then(() => this.updateFn.trigger());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -399,6 +399,4 @@ export class SlidingRoomListStoreClass extends AsyncStoreWithClient<IState> impl
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onAction(payload: ActionPayload): Promise<void> {}
|
protected async onAction(payload: ActionPayload): Promise<void> {}
|
||||||
|
|
||||||
protected async onDispatchAsync(payload: ActionPayload): Promise<void> {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,6 @@ export class Algorithm extends EventEmitter {
|
||||||
return this._stickyRoom ? this._stickyRoom.room : null;
|
return this._stickyRoom ? this._stickyRoom.room : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get knownRooms(): Room[] {
|
|
||||||
return this.rooms;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get hasTagSortingMap(): boolean {
|
public get hasTagSortingMap(): boolean {
|
||||||
return !!this.sortAlgorithms;
|
return !!this.sortAlgorithms;
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,10 +242,6 @@ export class StopGapWidget extends EventEmitter {
|
||||||
return parsed.toString().replace(/%24/g, "$");
|
return parsed.toString().replace(/%24/g, "$");
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isManagedByManager(): boolean {
|
|
||||||
return !!this.scalarToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get started(): boolean {
|
public get started(): boolean {
|
||||||
return !!this.messaging;
|
return !!this.messaging;
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
|
||||||
|
|
||||||
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
|
if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
|
||||||
|
|
||||||
let r: { event_id: string } | null = null; // eslint-disable-line camelcase
|
let r: { event_id: string } | null;
|
||||||
if (stateKey !== null) {
|
if (stateKey !== null) {
|
||||||
// state event
|
// state event
|
||||||
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
|
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
|
||||||
|
|
|
@ -411,45 +411,6 @@ export default class WidgetUtils {
|
||||||
return widgets.filter((w) => w.content?.type === "m.integration_manager");
|
return widgets.filter((w) => w.content?.type === "m.integration_manager");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getRoomWidgetsOfType(room: Room, type: WidgetType): MatrixEvent[] {
|
|
||||||
const widgets = WidgetUtils.getRoomWidgets(room) || [];
|
|
||||||
return widgets.filter((w) => {
|
|
||||||
const content = w.getContent();
|
|
||||||
return content.url && type.matches(content.type);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async removeIntegrationManagerWidgets(client: MatrixClient | undefined): Promise<void> {
|
|
||||||
if (!client) {
|
|
||||||
throw new Error("User not logged in");
|
|
||||||
}
|
|
||||||
const widgets = client.getAccountData("m.widgets");
|
|
||||||
if (!widgets) return;
|
|
||||||
const userWidgets: Record<string, IWidgetEvent> = widgets.getContent() || {};
|
|
||||||
Object.entries(userWidgets).forEach(([key, widget]) => {
|
|
||||||
if (widget.content && widget.content.type === "m.integration_manager") {
|
|
||||||
delete userWidgets[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
await client.setAccountData("m.widgets", userWidgets);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static addIntegrationManagerWidget(
|
|
||||||
client: MatrixClient,
|
|
||||||
name: string,
|
|
||||||
uiUrl: string,
|
|
||||||
apiUrl: string,
|
|
||||||
): Promise<void> {
|
|
||||||
return WidgetUtils.setUserWidget(
|
|
||||||
client,
|
|
||||||
"integration_manager_" + new Date().getTime(),
|
|
||||||
WidgetType.INTEGRATION_MANAGER,
|
|
||||||
uiUrl,
|
|
||||||
"Integration manager: " + name,
|
|
||||||
{ api_url: apiUrl },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all stickerpicker widgets (stickerpickers are user widgets by nature)
|
* Remove all stickerpicker widgets (stickerpickers are user widgets by nature)
|
||||||
* @param client The matrix client of the logged-in user
|
* @param client The matrix client of the logged-in user
|
||||||
|
|
|
@ -69,8 +69,4 @@ export class PermalinkParts {
|
||||||
public get primaryEntityId(): string | null {
|
public get primaryEntityId(): string | null {
|
||||||
return this.roomIdOrAlias || this.userId;
|
return this.roomIdOrAlias || this.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get sigil(): string {
|
|
||||||
return this.primaryEntityId?.[0] || "?";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ export class RoomPermalinkCreator {
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
|
if (this.started) return;
|
||||||
this.load();
|
this.load();
|
||||||
this.room?.currentState.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
this.room?.currentState.on(RoomStateEvent.Update, this.onRoomStateUpdate);
|
||||||
this.started = true;
|
this.started = true;
|
||||||
|
@ -128,10 +129,6 @@ export class RoomPermalinkCreator {
|
||||||
return this._serverCandidates;
|
return this._serverCandidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isStarted(): boolean {
|
|
||||||
return this.started;
|
|
||||||
}
|
|
||||||
|
|
||||||
public forEvent(eventId: string): string {
|
public forEvent(eventId: string): string {
|
||||||
return getPermalinkConstructor().forEvent(this.roomId, eventId, this._serverCandidates);
|
return getPermalinkConstructor().forEvent(this.roomId, eventId, this._serverCandidates);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ describe("transforming search term", () => {
|
||||||
eventId: "",
|
eventId: "",
|
||||||
userId: "",
|
userId: "",
|
||||||
viaServers: [],
|
viaServers: [],
|
||||||
sigil: "",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(transformSearchTerm(roomLink)).toBe(parsedPermalink);
|
expect(transformSearchTerm(roomLink)).toBe(parsedPermalink);
|
||||||
|
@ -46,7 +45,6 @@ describe("transforming search term", () => {
|
||||||
eventId: null,
|
eventId: null,
|
||||||
userId: null,
|
userId: null,
|
||||||
viaServers: null,
|
viaServers: null,
|
||||||
sigil: "?",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(transformSearchTerm(searchTerm)).toBe(searchTerm);
|
expect(transformSearchTerm(searchTerm)).toBe(searchTerm);
|
||||||
|
|
|
@ -12,6 +12,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { EventEmitter } from "events";
|
||||||
import { Room, RoomMember, EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { Room, RoomMember, EventType, MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
|
||||||
|
@ -87,6 +89,26 @@ describe("Permalinks", function () {
|
||||||
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
jest.spyOn(MatrixClientPeg, "get").mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not clean up listeners even if start was called multiple times", () => {
|
||||||
|
const room = mockRoom("!fake:example.org", []);
|
||||||
|
const getListenerCount = (emitter: EventEmitter) =>
|
||||||
|
emitter
|
||||||
|
.eventNames()
|
||||||
|
.map((e) => emitter.listenerCount(e))
|
||||||
|
.reduce((a, b) => a + b, 0);
|
||||||
|
const listenerCountBefore = getListenerCount(room.currentState);
|
||||||
|
|
||||||
|
const creator = new RoomPermalinkCreator(room);
|
||||||
|
creator.start();
|
||||||
|
creator.start();
|
||||||
|
creator.start();
|
||||||
|
creator.start();
|
||||||
|
expect(getListenerCount(room.currentState)).toBeGreaterThan(listenerCountBefore);
|
||||||
|
|
||||||
|
creator.stop();
|
||||||
|
expect(getListenerCount(room.currentState)).toBe(listenerCountBefore);
|
||||||
|
});
|
||||||
|
|
||||||
it("should pick no candidate servers when the room has no members", function () {
|
it("should pick no candidate servers when the room has no members", function () {
|
||||||
const room = mockRoom("!fake:example.org", []);
|
const room = mockRoom("!fake:example.org", []);
|
||||||
const creator = new RoomPermalinkCreator(room);
|
const creator = new RoomPermalinkCreator(room);
|
||||||
|
|
Loading…
Reference in a new issue