diff --git a/README.md b/README.md index c9c2b619fcec604a21514211028138ff5103c33a..5188a651f0243136c0fa63887eb53e67dbb3fd7a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Matrix Discord Bridge -A bridge between [Matrix](http://matrix.org/) and [Discord](https://discordapp.com/). +A bridge between [Matrix](http://matrix.org/) and [Discord](https://discord.com/). Currently the bridge is in **Beta** and quite usable for everyday bridging, with one or two bugs cropping up. - + ## Helping out @@ -88,8 +88,8 @@ file. The metrics will be reported under the URL provided in the registration fi #### 3PID Protocol Support This bridge support searching for rooms within networks via the 3pid system -used in clients like [Riot](https://riot.im). Any new servers/guilds you bridge -should show up in the network list on Riot and other clients. +used in clients like [Element](https://element.io). Any new servers/guilds you bridge +should show up in the network list on Element and other clients. ### Setting up Discord @@ -99,7 +99,7 @@ should show up in the network list on Riot and other clients. * Give this link to owners of the guilds you plan to bridge. * Finally, you can join a room with ``#_discord_guildid_channelid`` * These can be taken from the url ("/$GUILDID/$CHANNELID") when you are in a channel. - * Riot (and other clients with third party protocol support) users can directly join channels from the room directory. + * Element (and other clients with third party protocol support) users can directly join channels from the room directory. * You can use Webhooks to make messages relayed by the bridge not nested by the bot user. This will also display the avatar of the user speaking on matrix with their messages. * The bot should create this automatically, but if not perform the following: * Enable ``Manage Webhooks`` on the role added by the bot. diff --git a/config/config.sample.yaml b/config/config.sample.yaml index 9f66f8f35ebdd7697fd0fb10b6ce5d8cc095c504..07c3539ac470b29d9d4c6f92e1052bfbf794f48c 100644 --- a/config/config.sample.yaml +++ b/config/config.sample.yaml @@ -1,11 +1,11 @@ -# This is a sample of the config file showing all avaliable options. +# This is a sample of the config file showing all available options. # Where possible we have documented what they do, and all values are the # default values. bridge: # Domain part of the bridge, e.g. matrix.org domain: "localhost" - # This should be your publically facing URL because Discord may use it to + # This should be your publicly-facing URL because Discord may use it to # fetch media from the media store. homeserverUrl: "http://localhost:8008" # The TCP port on which the appservice runs on. @@ -40,7 +40,7 @@ auth: # This MUST be a string (wrapped in quotes) clientID: "12345" botToken: "foobar" - # You must enable "Privileged Gateway Intents" in your bot settings on discord.com (e.g.g https://discord.com/developers/applications/12345/bot) + # You must enable "Privileged Gateway Intents" in your bot settings on discord.com (e.g. https://discord.com/developers/applications/12345/bot) # for this to work usePrivilegedIntents: false logging: @@ -86,14 +86,14 @@ channel: unsetRoomAlias: true # Remove the room from the directory. unlistFromDirectory: true - # Set the room to be unavaliable for joining without an invite. + # Set the room to be unavailable for joining without an invite. setInviteOnly: true # Make all the discord users leave the room. ghostsLeave: true limits: # Delay in milliseconds between discord users joining a room. roomGhostJoinDelay: 6000 - # Lock timeout in milliseconds before seinding messages to discord to avoid + # Lock timeout in milliseconds before sending messages to discord to avoid # echos. Default is rather high as the lock will most likely time out # before anyways. # echos = (Copies of a sent message may arrive from discord before we've @@ -104,3 +104,8 @@ ghosts: nickPattern: ":nick" # Pattern for the ghosts username, available is :username, :tag and :id usernamePattern: ":username#:tag" +# Prometheus-compatible metrics endpoint +metrics: + enabled: false + port: 9001 + host: "127.0.0.1" \ No newline at end of file diff --git a/config/config.schema.yaml b/config/config.schema.yaml index 39427476032e864240785f972383166ecf9da31b..560508e582cad9f167a0a27fd3cba30fa71023e9 100644 --- a/config/config.schema.yaml +++ b/config/config.schema.yaml @@ -124,3 +124,12 @@ properties: type: "string" usernamePattern: type: "string" + metrics: + type: "object" + properties: + enabled: + type: "boolean" + port: + type: "number" + host: + type: "string" diff --git a/docs/howto.md b/docs/howto.md index f43902f5b683228d426dabb541354ff0b4538d32..3657a390e0f7641770321950ab684d40cab68bfb 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -7,19 +7,19 @@ The default format for room aliases (which are automatically resolved, whether t You can find these on discord in the browser where: -``https://discordapp.com/channels/282616294245662720/282616372591329281`` +``https://discord.com/channels/282616294245662720/282616372591329281`` -is formatted as https://discordapp.com/channels/``guildid``/``channelid`` +is formatted as https://discord.com/channels/``guildid``/``channelid`` ### Set privileges on bridge managed rooms * The ``adminme`` script is provided to set Admin/Moderator or any other custom power level to a specific user. * e.g. To set Alice to Admin on her ``example.com`` HS on default config. (``config.yaml``) - * ``npm run adminme -- -m '!AbcdefghijklmnopqR:example.com' -u '@Alice:example.com' -p '100'`` + * ``npm run adminme -- -r '!AbcdefghijklmnopqR:example.com' -u '@Alice:example.com' -p '100'`` * Run ``npm run adminme -- -h`` for usage. Please note that `!AbcdefghijklmnopqR:example.com` is the internal room id and will always begin with `!`. -You can find this internal id in the room settings in Riot. +You can find this internal id in the room settings in Element. ### Migrate to postgres from sqlite * Stop the bridge. diff --git a/src/bot.ts b/src/bot.ts index 4969b885fca68c194884d630c0b67d0d2346f9dc..9ff57af9e03946cce9e4a732e9a40601a205bd3c 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -94,7 +94,7 @@ export class DiscordBot { this.clientFactory = new DiscordClientFactory(store, config.auth); this.discordMsgProcessor = new DiscordMessageProcessor(config.bridge.domain, this); this.presenceHandler = new PresenceHandler(this); - this.roomHandler = new MatrixRoomHandler(this, config, this.provisioner, bridge, store.roomStore); + this.roomHandler = new MatrixRoomHandler(this, config, bridge, store.roomStore); this.channelSync = new ChannelSyncroniser(bridge, config, this, store.roomStore); this.provisioner = new Provisioner(store.roomStore, this.channelSync); this.mxEventProcessor = new MatrixEventProcessor( @@ -340,7 +340,7 @@ export class DiscordBot { public ThirdpartySearchForChannels(guildId: string, channelName: string): IThirdPartyLookup[] { if (channelName.startsWith("#")) { - channelName = channelName.substr(1); + channelName = channelName.substring(1); } if (this.bot.guilds.cache.has(guildId) ) { const guild = this.bot.guilds.cache.get(guildId); @@ -467,7 +467,7 @@ export class DiscordBot { }); return; } - const link = `https://discordapp.com/channels/${chan.guild.id}/${chan.id}/${editEventId}`; + const link = `https://discord.com/channels/${chan.guild.id}/${chan.id}/${editEventId}`; embedSet.messageEmbed.description = `[Edit](${link}): ${embedSet.messageEmbed.description}`; await this.send(embedSet, opts, roomLookup, event); } catch (err) { diff --git a/src/clientfactory.ts b/src/clientfactory.ts index f43ca851b81036dca8dec080c19f345bf98ebeba..b8f949fc07d786322ab94e6aa71d6dfe91e4babe 100644 --- a/src/clientfactory.ts +++ b/src/clientfactory.ts @@ -43,7 +43,7 @@ export class DiscordClientFactory { fetchAllMembers: this.config.usePrivilegedIntents, messageCacheLifetime: 5, ws: { - intents: this.config.usePrivilegedIntents ? Intents.PRIVILEGED : Intents.NON_PRIVILEGED, + intents: this.config.usePrivilegedIntents ? Intents.ALL : Intents.NON_PRIVILEGED, }, }); diff --git a/src/db/postgres.ts b/src/db/postgres.ts index da0d800e0de916bd03c8b76cd928531763cd4f8d..e4503bfb35f0276102344bda1e3c424680b7a1d2 100644 --- a/src/db/postgres.ts +++ b/src/db/postgres.ts @@ -26,7 +26,7 @@ const pgp: pgPromise.IMain = pgPromise({ export class Postgres implements IDatabaseConnector { public static ParameterizeSql(sql: string): string { return sql.replace(/\$((\w|\d|_)+)+/g, (k: string) => { - return `\${${k.substr("$".length)}}`; + return `\${${k.substring("$".length)}}`; }); } @@ -38,7 +38,7 @@ export class Postgres implements IDatabaseConnector { public Open(): void { // Hide username:password - const logConnString = this.connectionString.substr( + const logConnString = this.connectionString.substring( this.connectionString.indexOf("@") || 0, ); log.info(`Opening ${logConnString}`); diff --git a/src/log.ts b/src/log.ts index c33c4395407ba5551578fe8bcf1570bdf6588870..085b7b223634139d70d020bfb9dee8ce71a4d67a 100644 --- a/src/log.ts +++ b/src/log.ts @@ -46,6 +46,10 @@ export class Log { private static config: DiscordBridgeConfigLogging; private static logger: Logger; + private static isValidLevel(level: string) { + return ["silly", "verbose", "info", "http", "warn", "error", "silent"].includes(level); + } + private static setupLogger(): void { if (Log.logger) { Log.logger.close(); @@ -53,6 +57,9 @@ export class Log { const tsports: transports.StreamTransportInstance[] = Log.config.files.map((file) => Log.setupFileTransport(file), ); + if (Log.config.console && !Log.isValidLevel(Log.config.console)) { + new Log("Log").warn("Console log level is invalid. Please pick one of the case-sensitive levels provided in the sample config."); + } tsports.push(new transports.Console({ level: Log.config.console, })); @@ -80,6 +87,10 @@ export class Log { return info; }); + if (config.level && !Log.isValidLevel(config.level)) { + new Log("Log").warn(`Log level of ${config.file} is invalid. Please pick one of the case-sensitive levels provided in the sample config.`); + } + const opts = { datePattern: config.datePattern, filename: config.file, diff --git a/src/matrixeventprocessor.ts b/src/matrixeventprocessor.ts index 3a0af9548e0cef50aba399074830c5d28eaee04f..af4eb566a912cc27dae56b4a9c8534264fea7830 100644 --- a/src/matrixeventprocessor.ts +++ b/src/matrixeventprocessor.ts @@ -530,7 +530,7 @@ export class MatrixEventProcessor { } } embed.setAuthor( - displayName.substr(0, MAX_NAME_LENGTH), + displayName.substring(0, MAX_NAME_LENGTH), avatarUrl, `https://matrix.to/#/${sender}`, ); diff --git a/src/matrixroomhandler.ts b/src/matrixroomhandler.ts index b52ac3128d7e5bccbe97b6eac8189f2051df81d9..6689fa7372c0f6818143d206f458ec229a42197b 100644 --- a/src/matrixroomhandler.ts +++ b/src/matrixroomhandler.ts @@ -19,7 +19,6 @@ import { DiscordBridgeConfig } from "./config"; import * as Discord from "better-discord.js"; import { Util } from "./util"; -import { Provisioner } from "./provisioner"; import { Log } from "./log"; const log = new Log("MatrixRoomHandler"); import { DbRoomStore, MatrixStoreRoom, RemoteStoreRoom } from "./db/roomstore"; @@ -45,16 +44,12 @@ const JOIN_ROOM_SCHEDULE = [ export class MatrixRoomHandler { private botUserId: string; - private botJoinedRooms: Set<string>; // roomids - private botJoinedRoomsCacheUpdatedAt = 0; constructor( private discord: DiscordBot, private config: DiscordBridgeConfig, - private provisioner: Provisioner, private bridge: Appservice, private roomStore: DbRoomStore) { this.botUserId = this.discord.BotUserId; - this.botJoinedRooms = new Set(); } public bindThirdparty() { @@ -145,9 +140,9 @@ export class MatrixRoomHandler { // eslint-disable-next-line @typescript-eslint/no-explicit-any public async OnAliasQuery(alias: string): Promise<any> { - const aliasLocalpart = alias.substr("#".length, alias.indexOf(":") - 1); + const aliasLocalpart = alias.substring("#".length, alias.indexOf(":")); log.info("Got request for #", aliasLocalpart); - const srvChanPair = aliasLocalpart.substr("_discord_".length).split("_", ROOM_NAME_PARTS); + const srvChanPair = aliasLocalpart.substring("_discord_".length).split("_", ROOM_NAME_PARTS); if (srvChanPair.length < ROOM_NAME_PARTS || srvChanPair[0] === "" || srvChanPair[1] === "") { log.warn(`Alias '${aliasLocalpart}' was missing a server and/or a channel`); return; diff --git a/src/presencehandler.ts b/src/presencehandler.ts index ebb7024e3d91fa399a4e374168d089d2977aa612..7ef667a11eb0ed84bd2ce227cbf15795694fd6e4 100644 --- a/src/presencehandler.ts +++ b/src/presencehandler.ts @@ -144,7 +144,7 @@ export class PresenceHandler { const intent = this.bot.GetIntentFromDiscordMember(user); try { await intent.ensureRegistered(); - await intent.underlyingClient.setPresenceStatus(status.Presence, status.StatusMsg); + await intent.underlyingClient.setPresenceStatus(status.Presence, status.StatusMsg || ""); } catch (ex) { if (ex.errcode !== "M_FORBIDDEN") { log.warn(`Could not update Matrix presence for ${user.id}`); diff --git a/src/usersyncroniser.ts b/src/usersyncroniser.ts index 6400ecb7cb866a7a6e6a5c7af00385cba58472cf..51805200672eb67f4ea4d424896b10dde89f7036 100644 --- a/src/usersyncroniser.ts +++ b/src/usersyncroniser.ts @@ -114,7 +114,7 @@ export class UserSyncroniser { log.info(`Creating new user ${userState.mxUserId}`); remoteUser = new RemoteUser(userState.id); await this.userStore.linkUsers( - userState.mxUserId.substr("@".length), + userState.mxUserId.substring("@".length), userState.id, ); diff --git a/src/util.ts b/src/util.ts index 2bbf4122b415ccf4bc32a308e62ea8914fd7df2d..82bd985bd27c75ec133b7241ad6dbc20c4dd3f87 100644 --- a/src/util.ts +++ b/src/util.ts @@ -121,7 +121,7 @@ export class Util { const clientId = config.auth.clientID; - return `https://discordapp.com/api/oauth2/authorize?client_id=${clientId}&scope=bot&permissions=${perms}`; + return `https://discord.com/api/oauth2/authorize?client_id=${clientId}&scope=bot&permissions=${perms}`; } public static async GetMxidFromName(intent: Intent, name: string, channelMxids: string[]) { @@ -358,7 +358,7 @@ export class Util { public static ParseMxid(unescapedMxid: string, escape: boolean = true) { const RADIX = 16; - const parts = unescapedMxid.substr(1).split(":"); + const parts = unescapedMxid.substring(1).split(":"); const domain = parts[1]; let localpart = parts[0]; if (escape) { diff --git a/test/db/test_roomstore.ts b/test/db/test_roomstore.ts index 921550de72fc52246014d0daace1d3081f578b63..f9b0b0fe08c4820578070eb616ebfb64cd28416f 100644 --- a/test/db/test_roomstore.ts +++ b/test/db/test_roomstore.ts @@ -15,16 +15,13 @@ limitations under the License. */ /* eslint-disable @typescript-eslint/camelcase */ -import * as Chai from "chai"; +import { expect } from "chai"; import { DiscordStore, CURRENT_SCHEMA } from "../../src/store"; import { RemoteStoreRoom, MatrixStoreRoom } from "../../src/db/roomstore"; // we are a test file and thus need those /* tslint:disable: no-any no-unused-expression */ -const expect = Chai.expect; - -// const assert = Chai.assert; let store: DiscordStore; describe("RoomStore", () => { before(async () => { diff --git a/test/test_clientfactory.ts b/test/test_clientfactory.ts index ad2a29dca396bf2bfa26af8f620b88fde2632d03..7c1d865c869668cd6328f47ecca805bb7e3c1b7b 100644 --- a/test/test_clientfactory.ts +++ b/test/test_clientfactory.ts @@ -76,13 +76,13 @@ describe("ClientFactory", () => { describe("getDiscordId", () => { it("should fetch id successfully", async () => { const config = new DiscordBridgeConfigAuth(); - const cf = new DiscordClientFactory(null); + const cf = new DiscordClientFactory(null, config); const discordId = await cf.getDiscordId("passme"); expect(discordId).equals("12345"); }); it("should fail if the token is not recognised", async () => { const config = new DiscordBridgeConfigAuth(); - const cf = new DiscordClientFactory(null); + const cf = new DiscordClientFactory(null, config); try { await cf.getDiscordId("failme"); throw new Error("didn't fail"); @@ -102,7 +102,7 @@ describe("ClientFactory", () => { }); it("should return cached client", async () => { const config = new DiscordBridgeConfigAuth(); - const cf = new DiscordClientFactory(null); + const cf = new DiscordClientFactory(null, config); cf.clients.set("@user:localhost", "testclient"); const client = await cf.getClient("@user:localhost"); expect(client).equals("testclient"); @@ -116,14 +116,14 @@ describe("ClientFactory", () => { }); it("should fetch user client if userid matches", async () => { const config = new DiscordBridgeConfigAuth(); - const cf = new DiscordClientFactory(STORE); + const cf = new DiscordClientFactory(STORE, config); const client = await cf.getClient("@valid:localhost"); expect(client).is.not.null; expect(cf.clients.has("@valid:localhost")).to.be.true; }); it("should fail if the user client cannot log in", async () => { const config = new DiscordBridgeConfigAuth(); - const cf = new DiscordClientFactory(STORE); + const cf = new DiscordClientFactory(STORE, config); cf.botClient = 1; const client = await cf.getClient("@invalid:localhost"); expect(client).to.equal(cf.botClient); diff --git a/test/test_discordcommandhandler.ts b/test/test_discordcommandhandler.ts index 7589f486f983dcd2613f4b7d053080a49ebd9699..d29ee9b09a9f157e953c283451786626d2b48e9e 100644 --- a/test/test_discordcommandhandler.ts +++ b/test/test_discordcommandhandler.ts @@ -13,7 +13,7 @@ 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 * as Chai from "chai"; +import { expect } from "chai"; import * as Proxyquire from "proxyquire"; import { MockChannel } from "./mocks/channel"; @@ -25,8 +25,6 @@ import { AppserviceMock } from "./mocks/appservicemock"; // we are a test file and thus need those /* tslint:disable:no-unused-expression max-file-line-count no-any */ -const expect = Chai.expect; - let ROOMSUNBRIDGED = 0; let MARKED = -1; function createCH(opts: any = {}) { diff --git a/test/test_discordmessageprocessor.ts b/test/test_discordmessageprocessor.ts index 8ea322a29fd0bf5f9323399d4d81b2404a92972b..2ff272d859e0b11f89ae4d6455415bbd41f915de 100644 --- a/test/test_discordmessageprocessor.ts +++ b/test/test_discordmessageprocessor.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as Chai from "chai"; // TODO: Use expect +import { expect } from "chai"; import * as Discord from "better-discord.js"; import { DiscordMessageProcessor } from "../src/discordmessageprocessor"; import { DiscordBot } from "../src/bot"; @@ -53,8 +53,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello World!"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello World!"); - Chai.assert.equal(result.formattedBody, "Hello World!"); + expect(result.body).to.equal("Hello World!"); + expect(result.formattedBody).to.equal("Hello World!"); }); it("processes markdown messages correctly.", async () => { const processor = new DiscordMessageProcessor( @@ -63,8 +63,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello *World*!"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello *World*!"); - Chai.assert.equal(result.formattedBody, "Hello <em>World</em>!"); + expect(result.body).to.equal("Hello *World*!"); + expect(result.formattedBody).to.equal("Hello <em>World</em>!"); }); it("processes non-discord markdown correctly.", async () => { const processor = new DiscordMessageProcessor( @@ -73,14 +73,14 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = ">inb4 tests"; let result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, ">inb4 tests"); - Chai.assert.equal(result.formattedBody, ">inb4 tests"); + expect(result.body).to.equal(">inb4 tests"); + expect(result.formattedBody).to.equal(">inb4 tests"); msg.embeds = []; msg.content = "[test](http://example.com)"; result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "[test](http://example.com)"); - Chai.assert.equal(result.formattedBody, + expect(result.body).to.equal("[test](http://example.com)"); + expect(result.formattedBody).to.equal( "[test](<a href=\"http://example.com\">http://example.com</a>)"); }); it("processes discord-specific markdown correctly.", async () => { @@ -90,8 +90,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "_ italic _"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "_ italic _"); - Chai.assert.equal(result.formattedBody, "<em> italic </em>"); + expect(result.body).to.equal("_ italic _"); + expect(result.formattedBody).to.equal("<em> italic </em>"); }); it("replaces @everyone correctly", async () => { const processor = new DiscordMessageProcessor( @@ -100,13 +100,13 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "hey @everyone!"; let result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "hey @everyone!"); - Chai.assert.equal(result.formattedBody, "hey @everyone!"); + expect(result.body).to.equal("hey @everyone!"); + expect(result.formattedBody).to.equal("hey @everyone!"); msg.mentions.everyone = true; result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "hey @room!"); - Chai.assert.equal(result.formattedBody, "hey @room!"); + expect(result.body).to.equal("hey @room!"); + expect(result.formattedBody).to.equal("hey @room!"); }); it("replaces @here correctly", async () => { const processor = new DiscordMessageProcessor( @@ -115,13 +115,13 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "hey @here!"; let result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "hey @here!"); - Chai.assert.equal(result.formattedBody, "hey @here!"); + expect(result.body).to.equal("hey @here!"); + expect(result.formattedBody).to.equal("hey @here!"); msg.mentions.everyone = true; result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "hey @room!"); - Chai.assert.equal(result.formattedBody, "hey @room!"); + expect(result.body).to.equal("hey @room!"); + expect(result.formattedBody).to.equal("hey @room!"); }); }); describe("InsertUser / HTML", () => { @@ -134,8 +134,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "<@12345>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "@_discord_12345:localhost"); - Chai.assert.equal(result.formattedBody, "<a href=\"https://matrix.to/#/@_discord_12345:l" + + expect(result.body).to.equal("@_discord_12345:localhost"); + expect(result.formattedBody).to.equal("<a href=\"https://matrix.to/#/@_discord_12345:l" + "ocalhost\">@_discord_12345:localhost</a>"); }); it("processes members with usernames correctly", async () => { @@ -148,8 +148,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "<@12345>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "TestUsername"); - Chai.assert.equal(result.formattedBody, "<a href=\"https://matrix.to/#/@_discord_123" + + expect(result.body).to.equal("TestUsername"); + expect(result.formattedBody).to.equal("<a href=\"https://matrix.to/#/@_discord_123" + "45:localhost\">TestUsername</a>"); }); it("processes members with nickname correctly", async () => { @@ -162,8 +162,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "<@12345>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "TestNickname"); - Chai.assert.equal(result.formattedBody, "<a href=\"https://matrix.to/#/@_disc" + + expect(result.body).to.equal("TestNickname"); + expect(result.formattedBody).to.equal("<a href=\"https://matrix.to/#/@_disc" + "ord_12345:localhost\">TestNickname</a>"); }); }); @@ -177,8 +177,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello <:hello:123456789>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello <:hello:123456789>"); - Chai.assert.equal(result.formattedBody, "Hello <:hello:123456789>"); + expect(result.body).to.equal("Hello <:hello:123456789>"); + expect(result.formattedBody).to.equal("Hello <:hello:123456789>"); }); it("processes emoji correctly", async () => { const processor = new DiscordMessageProcessor( @@ -190,8 +190,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello <:hello:3333333>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello :hello:"); - Chai.assert.equal(result.formattedBody, "Hello <img alt=\":hello:\" ti" + + expect(result.body).to.equal("Hello :hello:"); + expect(result.formattedBody).to.equal("Hello <img alt=\":hello:\" ti" + "tle=\":hello:\" height=\"32\" src=\"mxc://image\" data-mx-emoticon />"); }); }); @@ -206,8 +206,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello <#3333333>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello <#3333333>"); - Chai.assert.equal(result.formattedBody, "Hello <#3333333>"); + expect(result.body).to.equal("Hello <#3333333>"); + expect(result.formattedBody).to.equal("Hello <#3333333>"); }); it("processes channels correctly", async () => { const processor = new DiscordMessageProcessor( @@ -219,8 +219,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello <#456>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello #TestChannel"); - Chai.assert.equal(result.formattedBody, "Hello <a href=\"https://matrix.to/#/#_discord_123" + + expect(result.body).to.equal("Hello #TestChannel"); + expect(result.formattedBody).to.equal("Hello <a href=\"https://matrix.to/#/#_discord_123" + "_456:localhost\">#TestChannel</a>"); }); it("processes channels without alias correctly", async () => { @@ -233,8 +233,8 @@ describe("DiscordMessageProcessor", () => { msg.embeds = []; msg.content = "Hello <#678>"; const result = await processor.FormatMessage(msg); - Chai.assert.equal(result.body, "Hello <#678>"); - Chai.assert.equal(result.formattedBody, "Hello <#678>"); + expect(result.body).to.equal("Hello <#678>"); + expect(result.formattedBody).to.equal("Hello <#678>"); }); }); }); diff --git a/test/test_log.ts b/test/test_log.ts index 54984f7f72820c57873a9e704f3ee8906bec2251..b3ad9d11dc3aa0470a56cce55ef9bb1cbf3a4911 100644 --- a/test/test_log.ts +++ b/test/test_log.ts @@ -71,6 +71,24 @@ describe("Log", () => { expect(Log.config.files).to.not.be.empty; expect(Log.config.files[0].file).to.equal("./logfile.log"); }); + it("should warn if log level got misspelled", () => { + Log.Configure({ + console: "WARNING", + lineDateFormat: "HH:mm:ss", + }); + expect(loggedMessages).to.contain("Console log level is invalid. Please pick one of the case-sensitive levels provided in the sample config."); + }); + it("should warn if log level for a file got misspelled", () => { + Log.Configure({ + files: [ + { + file: "./logfile.log", + level: "WARNING", + }, + ], + }); + expect(loggedMessages).to.contain("Log level of ./logfile.log is invalid. Please pick one of the case-sensitive levels provided in the sample config."); + }); }); describe("ForceSilent", () => { it("should be silent", () => { diff --git a/test/test_matrixroomhandler.ts b/test/test_matrixroomhandler.ts index 5a25d01313df589908e465820d661f6036691d29..1a9896eee2b80b84a4e343b869dd3c052ec36359 100644 --- a/test/test_matrixroomhandler.ts +++ b/test/test_matrixroomhandler.ts @@ -26,7 +26,7 @@ import { AppserviceMock } from "./mocks/appservicemock"; // we are a test file and thus need those /* tslint:disable:no-unused-expression max-file-line-count no-any */ -const RoomHandler = (Proxyquire("../src/matrixroomhandler", { +const MatrixRoomHandler = (Proxyquire("../src/matrixroomhandler", { "./util": { Util: { DelayedPromise: Util.DelayedPromise, @@ -105,23 +105,6 @@ function createRH(opts: any = {}) { } else { config.bridge.enableSelfServiceBridging = true; } - const provisioner = { - AskBridgePermission: async () => { - if (opts.denyBridgePermission) { - throw new Error("The bridge has been declined by the Discord guild"); - } - }, - BridgeMatrixRoom: () => { - if (opts.failBridgeMatrix) { - throw new Error("Test failed matrix bridge"); - } - }, - UnbridgeRoom: async () => { - if (opts.failUnbridge) { - throw new Error("Test failed unbridge"); - } - }, - }; const store = { getEntriesByMatrixId: (matrixId) => { return [{ @@ -136,7 +119,7 @@ function createRH(opts: any = {}) { }, }; - const handler = new RoomHandler(bot as any, config, provisioner as any, bridge as any, store); + const handler = new MatrixRoomHandler(bot as any, config, bridge as any, store); return { handler, bridge }; } diff --git a/test/test_presencehandler.ts b/test/test_presencehandler.ts index 8b1bf490f03c2dc8e090e232f82baeee50e35905..cbf4d057d4395e9474cedd25fe4e775274c40514 100644 --- a/test/test_presencehandler.ts +++ b/test/test_presencehandler.ts @@ -98,7 +98,7 @@ describe("PresenceHandler", () => { const member = new MockPresence(new MockUser("ghi", "alice"), "def", "online"); await handler.ProcessUser(member as any); appservice.getIntentForSuffix(member.userID) - .underlyingClient.wasCalled("setPresenceStatus", true, "online", undefined); + .underlyingClient.wasCalled("setPresenceStatus", true, "online", ""); }); it("processes an offline user", async () => { lastStatus = null; @@ -106,7 +106,7 @@ describe("PresenceHandler", () => { const member = new MockPresence(new MockUser("abc", "alice"), "def", "offline"); await handler.ProcessUser(member as any); appservice.getIntentForSuffix(member.userID) - .underlyingClient.wasCalled("setPresenceStatus", true, "offline", undefined); + .underlyingClient.wasCalled("setPresenceStatus", true, "offline", ""); }); it("processes an idle user", async () => { lastStatus = null; @@ -114,7 +114,7 @@ describe("PresenceHandler", () => { const member = new MockPresence(new MockUser("abc", "alice"), "def", "idle"); await handler.ProcessUser(member as any); appservice.getIntentForSuffix(member.userID) - .underlyingClient.wasCalled("setPresenceStatus", true, "unavailable", undefined); + .underlyingClient.wasCalled("setPresenceStatus", true, "unavailable", ""); }); it("processes an dnd user", async () => { lastStatus = null; diff --git a/test/test_store.ts b/test/test_store.ts index 3606edd49564a11358de09b46f87a4fd4b85c616..d2d735d7e629bf018ba539433db3844e36ad1f71 100644 --- a/test/test_store.ts +++ b/test/test_store.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import * as Chai from "chai"; +import { expect } from "chai"; import { DiscordStore } from "../src/store"; import { DbEmoji } from "../src/db/dbdataemoji"; import { DbEvent } from "../src/db/dbdataevent"; @@ -57,14 +57,14 @@ describe("DiscordStore", () => { insertEmoji.MxcUrl = "TestUrl"; await store.Insert(insertEmoji); const getEmoji = await store.Get(DbEmoji, {emoji_id: "123"}); - Chai.assert.equal(getEmoji!.Name, "TestEmoji"); - Chai.assert.equal(getEmoji!.MxcUrl, "TestUrl"); + expect(getEmoji!.Name).to.equal("TestEmoji"); + expect(getEmoji!.MxcUrl).to.equal("TestUrl"); }); it("should not return nonexistant emoji", async () => { const store = new DiscordStore(":memory:"); await store.init(); const getEmoji = await store.Get(DbEmoji, {emoji_id: "123"}); - Chai.assert.isFalse(getEmoji!.Result); + expect(getEmoji!.Result).to.be.false; }); it("should update successfully", async () => { const store = new DiscordStore(":memory:"); @@ -81,9 +81,9 @@ describe("DiscordStore", () => { insertEmoji.MxcUrl = "NewURL"; await store.Update(insertEmoji); const getEmoji = await store.Get(DbEmoji, {emoji_id: "123"}); - Chai.assert.equal(getEmoji!.Name, "TestEmoji2"); - Chai.assert.equal(getEmoji!.MxcUrl, "NewURL"); - Chai.assert.notEqual(getEmoji!.CreatedAt, getEmoji!.UpdatedAt); + expect(getEmoji!.Name).to.equal("TestEmoji2"); + expect(getEmoji!.MxcUrl).to.equal("NewURL"); + expect(getEmoji!.CreatedAt).to.not.equal(getEmoji!.UpdatedAt); }); }); describe("Get|Insert|Delete<DbEvent>", () => { @@ -108,16 +108,16 @@ describe("DiscordStore", () => { await store.Insert(event); const getEventDiscord = await store.Get(DbEvent, {discord_id: "456"}); getEventDiscord!.Next(); - Chai.assert.equal(getEventDiscord!.MatrixId, "123"); - Chai.assert.equal(getEventDiscord!.DiscordId, "456"); - Chai.assert.equal(getEventDiscord!.GuildId, "123"); - Chai.assert.equal(getEventDiscord!.ChannelId, "123"); + expect(getEventDiscord!.MatrixId).to.equal("123"); + expect(getEventDiscord!.DiscordId).to.equal("456"); + expect(getEventDiscord!.GuildId).to.equal("123"); + expect(getEventDiscord!.ChannelId).to.equal("123"); const getEventMatrix = await store.Get(DbEvent, {matrix_id: "123"}); getEventMatrix!.Next(); - Chai.assert.equal(getEventMatrix!.MatrixId, "123"); - Chai.assert.equal(getEventMatrix!.DiscordId, "456"); - Chai.assert.equal(getEventMatrix!.GuildId, "123"); - Chai.assert.equal(getEventMatrix!.ChannelId, "123"); + expect(getEventMatrix!.MatrixId).to.equal("123"); + expect(getEventMatrix!.DiscordId).to.equal("456"); + expect(getEventMatrix!.GuildId).to.equal("123"); + expect(getEventMatrix!.ChannelId).to.equal("123"); }); const MSG_COUNT = 5; it("should get multiple discord msgs successfully", async () => { @@ -132,7 +132,7 @@ describe("DiscordStore", () => { await store.Insert(event); } const getEventDiscord = await store.Get(DbEvent, {matrix_id: "123"}); - Chai.assert.equal(getEventDiscord!.ResultCount, MSG_COUNT); + expect(getEventDiscord!.ResultCount).to.equal(MSG_COUNT); }); it("should get multiple matrix msgs successfully", async () => { const store = new DiscordStore(":memory:"); @@ -146,13 +146,13 @@ describe("DiscordStore", () => { await store.Insert(event); } const getEventMatrix = await store.Get(DbEvent, {discord_id: "456"}); - Chai.assert.equal(getEventMatrix!.ResultCount, MSG_COUNT); + expect(getEventMatrix!.ResultCount).to.equal(MSG_COUNT); }); it("should not return nonexistant event", async () => { const store = new DiscordStore(":memory:"); await store.init(); const getMessage = await store.Get(DbEvent, {matrix_id: "123"}); - Chai.assert.isFalse(getMessage!.Result); + expect(getMessage!.Result).to.be.false; }); it("should delete successfully", async () => { const store = new DiscordStore(":memory:"); @@ -166,7 +166,7 @@ describe("DiscordStore", () => { await store.Delete(event); const getEvent = await store.Get(DbEvent, {matrix_id: "123"}); getEvent!.Next(); - Chai.assert.isFalse(getEvent!.Result); + expect(getEvent!.Result).to.be.false; }); }); });