-
Notifications
You must be signed in to change notification settings - Fork 153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Automatically create mapped channels if mappings[...].createRoom
is set
#1099
base: develop
Are you sure you want to change the base?
Changes from all commits
91668c2
e74dfae
45f0ead
2a13922
a516514
4917a92
adcec3e
6455276
fc5bd83
511f26c
260e93e
518c21d
a4d6f3a
0c35217
9582253
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add the ability to create rooms automatically for mapped channels in the config. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
const envBundle = require("../util/env-bundle"); | ||
|
||
describe("Static channels", function() { | ||
const staticTestChannel = "#astaticchannel"; | ||
const generatedTestChannel = "#ageneratedchannel"; | ||
const generatedRoomId = "!gen:bar"; | ||
const {env, config, roomMapping, botUserId, test} = envBundle(); | ||
|
||
beforeEach(async function() { | ||
config.ircService.servers[roomMapping.server].mappings[staticTestChannel] = { | ||
roomIds: ["!foo:bar"], | ||
}; | ||
|
||
config.ircService.servers[roomMapping.server].mappings[generatedTestChannel] = { | ||
createRoom: true, | ||
}; | ||
|
||
await test.beforeEach(env); | ||
|
||
env.ircMock._autoConnectNetworks( | ||
roomMapping.server, roomMapping.botNick, roomMapping.server | ||
); | ||
|
||
// Ensure rooms are created on startup | ||
sdk = env.clientMock._client(botUserId); | ||
sdk.createRoom.and.callFake(async function(opts) { | ||
return { | ||
room_id: generatedRoomId | ||
}; | ||
}); | ||
|
||
await test.initEnv(env, config); | ||
}); | ||
|
||
afterEach(async function() { | ||
await test.afterEach(env); | ||
}); | ||
|
||
it("should insert static channel mappings to bridge store", async function () { | ||
const store = await env.ircBridge.getStore(); | ||
const server = await env.ircBridge.getServer(roomMapping.server); | ||
const mappings = await store.getMappingsForChannelByOrigin(server, staticTestChannel, "config"); | ||
expect(mappings.length).toEqual(1); | ||
const entry = mappings[0]; | ||
expect(entry.matrix.roomId).toEqual("!foo:bar"); | ||
expect(entry.remote.data).toEqual({ | ||
domain: roomMapping.server, | ||
channel: staticTestChannel, | ||
type: "channel", | ||
}); | ||
expect(entry.data.origin).toEqual("config"); | ||
}); | ||
|
||
it("should clear static channel mappings from bridge store", async function () { | ||
const store = await env.ircBridge.getStore(); | ||
const server = await env.ircBridge.getServer(roomMapping.server); | ||
await store.removeConfigMappings(server); | ||
const mappings = await store.getMappingsForChannelByOrigin(server, staticTestChannel, "config"); | ||
expect(mappings.length).toEqual(0); | ||
}); | ||
|
||
it("should create a channel mapping for mappings with createRoom", async function () { | ||
const store = await env.ircBridge.getStore(); | ||
const server = await env.ircBridge.getServer(roomMapping.server); | ||
const mappings = await store.getMappingsForChannelByOrigin(server, generatedTestChannel, "config"); | ||
expect(mappings.length).toEqual(1); | ||
const entry = mappings[0]; | ||
expect(entry.remote.data).toEqual({ | ||
domain: roomMapping.server, | ||
channel: generatedTestChannel, | ||
type: "channel", | ||
}); | ||
expect(entry.matrix.roomId).toEqual(generatedRoomId); | ||
expect(entry.data.origin).toEqual("config"); | ||
}); | ||
|
||
it("should NOT clear channel mappings for mappings with createRoom", async function () { | ||
const store = await env.ircBridge.getStore(); | ||
const server = await env.ircBridge.getServer(roomMapping.server); | ||
await store.removeConfigMappings(server); | ||
const mappings = await store.getMappingsForChannelByOrigin(server, generatedTestChannel, "config"); | ||
expect(mappings.length).toEqual(1); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,9 +91,15 @@ export class NeDBDataStore implements DataStore { | |
public async setServerFromConfig(server: IrcServer, serverConfig: IrcServerConfig): Promise<void> { | ||
this.serverMappings[server.domain] = server; | ||
|
||
for (const channel of Object.keys(serverConfig.mappings)) { | ||
await this.removeConfigMappings(server); | ||
|
||
for (const [channel, opts] of Object.entries(serverConfig.mappings)) { | ||
if (opts.createRoom) { | ||
return; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One opts.createRoom makes the entire setting of the server impossible? |
||
} | ||
log.info(`Mapping channel ${channel} to ${opts.roomIds.join(",")}`); | ||
const ircRoom = new IrcRoom(server, channel); | ||
for (const roomId of serverConfig.mappings[channel].roomIds) { | ||
for (const roomId of opts.roomIds) { | ||
const mxRoom = new MatrixRoom(roomId); | ||
await this.storeRoom(ircRoom, mxRoom, "config"); | ||
} | ||
|
@@ -413,13 +419,22 @@ export class NeDBDataStore implements DataStore { | |
}).filter((e) => e !== ""); | ||
} | ||
|
||
public async removeConfigMappings() { | ||
public async removeConfigMappings(server: IrcServer) { | ||
await this.roomStore.removeEntriesByLinkData({ | ||
from_config: true // for backwards compatibility | ||
}); | ||
await this.roomStore.removeEntriesByLinkData({ | ||
origin: 'config' | ||
// Filter for config entries which are from this network and are NOT autocreated. | ||
let entries = await this.roomStore.getEntriesByLinkData({ | ||
origin: 'config', | ||
}); | ||
const notChannels = server.getAutoCreateMappings().map((c) => c.channel); | ||
entries = (await entries).filter((e) => e.remote?.get("domain") === server.domain && | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. entries was already awaited two lines above. |
||
!notChannels.includes(e.remote?.get("channel") as string)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// Remove just these entries. | ||
for (const entry of entries) { | ||
await this.roomStore.delete({id: entry.id, "data.origin": "config"}); | ||
} | ||
} | ||
|
||
public async getIpv6Counter(): Promise<number> { | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -63,10 +63,19 @@ export class PgDataStore implements DataStore { | |||||
public async setServerFromConfig(server: IrcServer, serverConfig: IrcServerConfig): Promise<void> { | ||||||
this.serverMappings[server.domain] = server; | ||||||
|
||||||
for (const channel of Object.keys(serverConfig.mappings)) { | ||||||
await this.removeConfigMappings(server); | ||||||
|
||||||
for (const [channel, data] of Object.entries(serverConfig.mappings)) { | ||||||
if (data.createRoom) { | ||||||
// We don't want to map this. | ||||||
return; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Return, not continue?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a habit of mixing those up 😆 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .map and functions let you use your preferred return command. 😀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
if (!data.roomIds) { | ||||||
throw Error(`roomIds not given on ${channel} config entry`); | ||||||
} | ||||||
const ircRoom = new IrcRoom(server, channel); | ||||||
ircRoom.set("type", "channel"); | ||||||
for (const roomId of serverConfig.mappings[channel].roomIds) { | ||||||
for (const roomId of data.roomIds) { | ||||||
const mxRoom = new MatrixRoom(roomId); | ||||||
await this.storeRoom(ircRoom, mxRoom, "config"); | ||||||
} | ||||||
|
@@ -357,8 +366,25 @@ export class PgDataStore implements DataStore { | |||||
).rows.map((e) => e.room_id); | ||||||
} | ||||||
|
||||||
public async removeConfigMappings(): Promise<void> { | ||||||
await this.pgPool.query("DELETE FROM rooms WHERE origin = 'config'"); | ||||||
public async removeConfigMappings(server: IrcServer): Promise<void> { | ||||||
// We need to remove config mappings on startup so we can ensure what's in the config | ||||||
// matches what's in the database. The problem is that autogenerated rooms should not | ||||||
// be deleted as they will not be regenerated on startup. | ||||||
// | ||||||
// However, we *should* delete any of them that are no longer in the config, hence the | ||||||
// gnarly code below. | ||||||
let exclusionQuerys = []; | ||||||
console.log(server.getNetworkId(), server.getAutoCreateMappings()); | ||||||
for (const mapping of server.getAutoCreateMappings()) { | ||||||
exclusionQuerys.push(mapping.channel); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even though this comes from a config that only an admin can configure, I wish we would escape the channel names before putting them into an SQL statement. |
||||||
} | ||||||
let query = `DELETE FROM rooms WHERE origin = 'config' AND irc_domain = $1` | ||||||
if (exclusionQuerys.length) { | ||||||
query += ` AND irc_channel NOT IN ('${exclusionQuerys.join("','")}')`; | ||||||
} | ||||||
this.pgPool.query(query, [ | ||||||
server.domain, | ||||||
]); | ||||||
} | ||||||
|
||||||
public async getIpv6Counter(): Promise<number> { | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this?
... Looks up env-bundle...