diff --git a/config/config.sample.yaml b/config/config.sample.yaml index 7b3680e3904ee8c309b57dd01f5d6d6315927d4a..10f6d2fb97e7f9ca24fff97f962683894245c11b 100644 --- a/config/config.sample.yaml +++ b/config/config.sample.yaml @@ -90,5 +90,7 @@ limits: # fininished handling it, causing us to echo it back to the room) discordSendDelay: 750 ghosts: - # the tag to append to ghost nicknames - tag: "" + # Pattern for the ghosts nick, available is :nick, :username, :tag and :id + nickPattern: ":nick" + # Pattern for the ghosts username, available is :username, :tag and :id + usernamePattern: ":username#:tag" diff --git a/config/config.schema.yaml b/config/config.schema.yaml index 68ecba2af8dc808d77ae8ad9d7a7349874c133e0..7439ef2852c7af065ee69f2d91c8a476420b01da 100644 --- a/config/config.schema.yaml +++ b/config/config.schema.yaml @@ -112,5 +112,7 @@ properties: ghosts: type: "object" properties: - tag: + nickPattern: + type: "string" + usernamePattern: type: "string" diff --git a/src/channelsyncroniser.ts b/src/channelsyncroniser.ts index 8f76d9e15799f57ed29e63e61a9fd53878cce47d..c948f35da71df85004efa18ee4fbb802d0014d85 100644 --- a/src/channelsyncroniser.ts +++ b/src/channelsyncroniser.ts @@ -163,14 +163,10 @@ export class ChannelSyncroniser { return channelState; } - const patternMap = { + const name: string = Util.ApplyPatternString(this.config.channel.namePattern, { guild: channel.guild.name, name: "#" + channel.name, - }; - let name: string = this.config.channel.namePattern; - for (const p of Object.keys(patternMap)) { - name = name.replace(new RegExp(":" + p, "g"), patternMap[p]); - } + }); const topic = channel.topic; const icon = channel.guild.icon; let iconUrl: string | null = null; diff --git a/src/config.ts b/src/config.ts index b54ca4cf02da2d5f5e0512e2da1e487a988b4d4a..637bc555fb28450a2b2feccb5eb584eaa2c114fe 100644 --- a/src/config.ts +++ b/src/config.ts @@ -112,5 +112,6 @@ export class LoggingFile { } class DiscordBridgeConfigGhosts { - public tag: string = ""; + public nickPattern: string = ":nick"; + public usernamePattern: string = ":username#:tag"; } diff --git a/src/usersyncroniser.ts b/src/usersyncroniser.ts index 2af4dac34fa821e2b5fe3d28622f163dee20afa3..86e144b3bb9d999128bf47c52408764b0fa8a956 100644 --- a/src/usersyncroniser.ts +++ b/src/usersyncroniser.ts @@ -234,8 +234,11 @@ export class UserSyncroniser { id: discordUser.id, mxUserId: `@_discord_${discordUser.id}${mxidExtra}:${this.config.bridge.domain}`, }); - const displayName = this.displayNameForUser(discordUser) - + (this.config.ghosts.tag ? " " + this.config.ghosts.tag : ""); + const displayName = Util.ApplyPatternString(this.config.ghosts.usernamePattern, { + id: discordUser.id, + tag: discordUser.discriminator, + username: discordUser.username, + }); // Determine if the user exists. const remoteId = discordUser.id + mxidExtra; const remoteUser = await this.userStore.getRemoteUser(remoteId); @@ -271,10 +274,16 @@ export class UserSyncroniser { public async GetUserStateForGuildMember( newMember: GuildMember, ): Promise<IGuildMemberState> { + const name = Util.ApplyPatternString(this.config.ghosts.nickPattern, { + id: newMember.user.id, + nick: newMember.displayName, + tag: newMember.user.discriminator, + username: newMember.user.username, + }); const guildState: IGuildMemberState = Object.assign({}, DEFAULT_GUILD_STATE, { bot: newMember.user.bot, displayColor: newMember.displayColor, - displayName: newMember.displayName + (this.config.ghosts.tag ? " " + this.config.ghosts.tag : ""), + displayName: name, id: newMember.id, mxUserId: `@_discord_${newMember.id}:${this.config.bridge.domain}`, roles: newMember.roles.map((role) => { return { @@ -395,10 +404,6 @@ export class UserSyncroniser { }); } - private displayNameForUser(discordUser): string { - return `${discordUser.username}#${discordUser.discriminator}`; - } - private async leave(intent: Intent, roomId: string, checkCache: boolean = true) { const userId = intent.getClient().getUserId(); if (checkCache && ![null, "join", "invite"] diff --git a/src/util.ts b/src/util.ts index 8b606bbf40b61d67562c244414ab7c42a7265b8f..aca4d651a2eb9780ff8d1a5666b389799edb10db 100644 --- a/src/util.ts +++ b/src/util.ts @@ -47,6 +47,10 @@ export interface ICommandParameters { [index: string]: ICommandParameter; } +export interface IPatternMap { + [index: string]: string; +} + export class Util { /** * downloadFile - This function will take a URL and store the resulting data into @@ -274,6 +278,13 @@ export class Util { const htmlColor = pad.substring(0, pad.length - colorHex.length) + colorHex; return htmlColor; } + + public static ApplyPatternString(str: string, patternMap: IPatternMap): string { + for (const p of Object.keys(patternMap)) { + str = str.replace(new RegExp(":" + p, "g"), patternMap[p]); + } + return str; + } } interface IUploadResult { diff --git a/test/test_channelsyncroniser.ts b/test/test_channelsyncroniser.ts index c54aa2f1cd7e4ce0e728aa33428452351f95f691..7d90f6e827c782c1ca6f4ce11d618af0dd6ed124 100644 --- a/test/test_channelsyncroniser.ts +++ b/test/test_channelsyncroniser.ts @@ -24,6 +24,7 @@ import { MockGuild } from "./mocks/guild"; import { MockMember } from "./mocks/member"; import { MatrixEventProcessor, MatrixEventProcessorOpts } from "../src/matrixeventprocessor"; import { DiscordBridgeConfig } from "../src/config"; +import { Util } from "../src/util"; import { MockChannel } from "./mocks/channel"; import { Bridge, MatrixRoom, RemoteRoom } from "matrix-appservice-bridge"; // we are a test file and thus need those @@ -44,6 +45,7 @@ let ROOM_DIRECTORY_VISIBILITY: any = null; const ChannelSync = (Proxyquire("../src/channelsyncroniser", { "./util": { Util: { + ApplyPatternString: Util.ApplyPatternString, UploadContentFromUrl: async () => { UTIL_UPLOADED_AVATAR = true; return {mxcUrl: "avatarset"}; diff --git a/test/test_usersyncroniser.ts b/test/test_usersyncroniser.ts index 2984d293e8d77b25b4e98971ed0d4ac1673f68c9..531f3e86e1ded68fb2848882d750c9e195f128b9 100644 --- a/test/test_usersyncroniser.ts +++ b/test/test_usersyncroniser.ts @@ -55,6 +55,7 @@ const GUILD_ROOM_IDS_WITH_ROLE = ["!abc:localhost", "!def:localhost"]; const UserSync = (Proxyquire("../src/usersyncroniser", { "./util": { Util: { + ApplyPatternString: Util.ApplyPatternString, AsyncForEach: Util.AsyncForEach, UploadContentFromUrl: async () => { UTIL_UPLOADED_AVATAR = true; @@ -64,7 +65,7 @@ const UserSync = (Proxyquire("../src/usersyncroniser", { }, })).UserSyncroniser; -function CreateUserSync(remoteUsers: RemoteUser[] = [], nickTag: string = ""): UserSyncroniser { +function CreateUserSync(remoteUsers: RemoteUser[] = [], ghostConfig: any = {}): UserSyncroniser { UTIL_UPLOADED_AVATAR = false; SEV_ROOM_ID = null; SEV_CONTENT = null; @@ -153,7 +154,7 @@ function CreateUserSync(remoteUsers: RemoteUser[] = [], nickTag: string = ""): U }; const config = new DiscordBridgeConfig(); config.bridge.domain = "localhost"; - config.ghosts.tag = nickTag; + config.ghosts = Object.assign({}, config.ghosts, ghostConfig); return new UserSync(bridge as Bridge, config, discordbot, userStore as any); } @@ -197,12 +198,12 @@ describe("UserSyncroniser", () => { expect(state.avatarId, "AvatarID").is.empty; expect(state.avatarUrl, "AvatarUrl").is.null; }); - it("Will obay name tags", async () => { + it("Will obay name patterns", async () => { const remoteUser = new RemoteUser("123456"); remoteUser.avatarurl = "test.jpg"; remoteUser.displayname = "TestUsername"; - const userSync = CreateUserSync([remoteUser], "(Discord)"); + const userSync = CreateUserSync([remoteUser], {usernamePattern: ":username#:tag (Discord)"}); const user = new MockUser( "123456", "TestUsername", @@ -489,8 +490,8 @@ describe("UserSyncroniser", () => { const state = await userSync.GetUserStateForGuildMember(member as any); expect(state.displayName).to.be.equal("BestDog"); }); - it("Will will obay name tags", async () => { - const userSync = CreateUserSync([new RemoteUser("123456")], "(Discord)"); + it("Will will obay nick pattern", async () => { + const userSync = CreateUserSync([new RemoteUser("123456")], { nickPattern: ":nick (Discord)" }); const guild = new MockGuild( "654321"); const member = new MockMember(