diff --git a/src/api/admin/AdminIrcService.ts b/src/api/admin/AdminIrcService.ts index 2e17cca..f5c2310 100644 --- a/src/api/admin/AdminIrcService.ts +++ b/src/api/admin/AdminIrcService.ts @@ -6,6 +6,7 @@ import { ApiError } from "../ApiError"; import IrcBridgeRecord from "../../db/models/IrcBridgeRecord"; import { AvailableNetworks, IrcBridge } from "../../bridges/IrcBridge"; import Upstream from "../../db/models/Upstream"; +import IrcBridgeNetwork from "../../db/models/IrcBridgeNetwork"; interface CreateWithUpstream { upstreamId: number; @@ -23,6 +24,10 @@ interface BridgeResponse { availableNetworks: AvailableNetworks; } +interface SetEnabledRequest { + isEnabled: boolean; +} + /** * Administrative API for configuring IRC bridge instances. */ @@ -65,6 +70,31 @@ export class AdminIrcService { }; } + @POST + @Path(":bridgeId/network/:networkId/enabled") + public async setNetworkEnabled(@QueryParam("scalar_token") scalarToken: string, @PathParam("bridgeId") bridgeId: number, @PathParam("networkId") networkId: string, request: SetEnabledRequest): Promise { + const userId = await AdminService.validateAndGetAdminTokenOwner(scalarToken); + + const ircBridge = await IrcBridgeRecord.findByPrimary(bridgeId); + if (!ircBridge) throw new ApiError(404, "IRC Bridge not found"); + + const localNetworkId = IrcBridge.parseNetworkId(networkId).bridgeNetworkId; + const network = await IrcBridgeNetwork.findOne({ + where: { + bridgeId: ircBridge.id, + bridgeNetworkId: localNetworkId, + }, + }); + if (!network) throw new ApiError(404, "Network not found"); + + network.isEnabled = request.isEnabled; + await network.save(); + + LogService.info("AdminIrcService", userId + " toggled the network '" + localNetworkId + "' on bridge " + ircBridge.id); + Cache.for(CACHE_IRC_BRIDGE).clear(); + return {}; // 200 OK + } + @POST @Path("new/upstream") public async newConfigForUpstream(@QueryParam("scalar_token") scalarToken: string, request: CreateWithUpstream): Promise { diff --git a/src/bridges/IrcBridge.ts b/src/bridges/IrcBridge.ts index 700c839..ec943cf 100644 --- a/src/bridges/IrcBridge.ts +++ b/src/bridges/IrcBridge.ts @@ -34,7 +34,7 @@ export class IrcBridge { public static parseNetworkId(networkId: string): { bridgeId: string, bridgeNetworkId: string } { const parts = networkId.split("-"); - const bridgeId = parts.splice(1, 1)[0]; + const bridgeId = parts.splice(0, 1)[0]; const bridgeNetworkId = parts.join("-"); return {bridgeId, bridgeNetworkId}; } diff --git a/web/app/admin/bridges/irc/irc.component.ts b/web/app/admin/bridges/irc/irc.component.ts index ab86c37..f29403b 100644 --- a/web/app/admin/bridges/irc/irc.component.ts +++ b/web/app/admin/bridges/irc/irc.component.ts @@ -4,6 +4,8 @@ import { AdminIrcApiService } from "../../../shared/services/admin/admin-irc-api import { FE_Upstream } from "../../../shared/models/admin-responses"; import { AdminUpstreamApiService } from "../../../shared/services/admin/admin-upstream-api.service"; import { FE_IrcBridge } from "../../../shared/models/irc"; +import { Modal, overlayConfigFactory } from "ngx-modialog"; +import { AdminIrcBridgeNetworksComponent, IrcNetworksDialogContext } from "./networks/networks.component"; @Component({ templateUrl: "./irc.component.html", @@ -20,7 +22,8 @@ export class AdminIrcBridgeComponent implements OnInit { constructor(private upstreamApi: AdminUpstreamApiService, private ircApi: AdminIrcApiService, - private toaster: ToasterService) { + private toaster: ToasterService, + private modal: Modal) { } public ngOnInit() { @@ -88,6 +91,11 @@ export class AdminIrcBridgeComponent implements OnInit { } public editNetworks(bridge: FE_IrcBridge) { - console.log(bridge); + this.modal.open(AdminIrcBridgeNetworksComponent, overlayConfigFactory({ + bridge: bridge, + + isBlocking: true, + size: 'lg', + }, IrcNetworksDialogContext)); } } diff --git a/web/app/admin/bridges/irc/networks/networks.component.html b/web/app/admin/bridges/irc/networks/networks.component.html new file mode 100644 index 0000000..b93d7e0 --- /dev/null +++ b/web/app/admin/bridges/irc/networks/networks.component.html @@ -0,0 +1,29 @@ +
+
+

{{ bridge.upstreamId ? "matrix.org's" : "Self-hosted" }} IRC Bridge Networks

+
+
+ + + + + + + + + + + + + +
NetworkEnabled
{{ network.name }} + +
+
+ +
\ No newline at end of file diff --git a/web/app/admin/bridges/irc/networks/networks.component.scss b/web/app/admin/bridges/irc/networks/networks.component.scss new file mode 100644 index 0000000..344be0c --- /dev/null +++ b/web/app/admin/bridges/irc/networks/networks.component.scss @@ -0,0 +1,5 @@ +table tr th:last-child, +table tr td:last-child { + text-align: center; + width: 100px; +} \ No newline at end of file diff --git a/web/app/admin/bridges/irc/networks/networks.component.ts b/web/app/admin/bridges/irc/networks/networks.component.ts new file mode 100644 index 0000000..d65b821 --- /dev/null +++ b/web/app/admin/bridges/irc/networks/networks.component.ts @@ -0,0 +1,63 @@ +import { Component } from "@angular/core"; +import { ToasterService } from "angular2-toaster"; +import { DialogRef, ModalComponent } from "ngx-modialog"; +import { BSModalContext } from "ngx-modialog/plugins/bootstrap"; +import { FE_IrcBridge } from "../../../../shared/models/irc"; +import { AdminIrcApiService } from "../../../../shared/services/admin/admin-irc-api.service"; + +export class IrcNetworksDialogContext extends BSModalContext { + public bridge: FE_IrcBridge; +} + +interface LocalNetwork { + id: string; + name: string; + domain: string; + bridgeUserId: string; + isEnabled: boolean; +} + +@Component({ + templateUrl: "./networks.component.html", + styleUrls: ["./networks.component.scss"], +}) +export class AdminIrcBridgeNetworksComponent implements ModalComponent { + + public isUpdating = false; + public bridge: FE_IrcBridge; + public networks: LocalNetwork[]; + + constructor(public dialog: DialogRef, + private ircApi: AdminIrcApiService, + private toaster: ToasterService) { + this.bridge = dialog.context.bridge; + + const networkIds = Object.keys(this.bridge.availableNetworks); + this.networks = networkIds.map(i => { + return { + id: i, + name: this.bridge.availableNetworks[i].name, + domain: this.bridge.availableNetworks[i].domain, + bridgeUserId: this.bridge.availableNetworks[i].bridgeUserId, + isEnabled: this.bridge.availableNetworks[i].isEnabled, + }; + }); + } + + public toggleNetwork(network: LocalNetwork) { + network.isEnabled = !network.isEnabled; + this.bridge.availableNetworks[network.id].isEnabled = network.isEnabled; + + this.isUpdating = true; + this.ircApi.setNetworkEnabled(this.bridge.id, network.id, network.isEnabled).then(() => { + this.isUpdating = false; + this.toaster.pop("success", "Network " + (network.isEnabled ? "enabled" : "disabled")); + }).catch(err => { + console.error(err); + this.isUpdating = false; + network.isEnabled = !network.isEnabled; + this.bridge.availableNetworks[network.id].isEnabled = network.isEnabled; + this.toaster.pop("error", "Failed to update network"); + }); + } +} diff --git a/web/app/app.module.ts b/web/app/app.module.ts index 73ded73..5574b08 100644 --- a/web/app/app.module.ts +++ b/web/app/app.module.ts @@ -66,6 +66,7 @@ import { ConfigScreenBridgeComponent } from "./configs/bridge/config-screen/conf import { AdminBridgesComponent } from "./admin/bridges/bridges.component"; import { AdminIrcBridgeComponent } from "./admin/bridges/irc/irc.component"; import { AdminIrcApiService } from "./shared/services/admin/admin-irc-api.service"; +import { AdminIrcBridgeNetworksComponent } from "./admin/bridges/irc/networks/networks.component"; @NgModule({ imports: [ @@ -125,6 +126,7 @@ import { AdminIrcApiService } from "./shared/services/admin/admin-irc-api.servic ConfigScreenBridgeComponent, AdminBridgesComponent, AdminIrcBridgeComponent, + AdminIrcBridgeNetworksComponent, // Vendor ], @@ -154,6 +156,7 @@ import { AdminIrcApiService } from "./shared/services/admin/admin-irc-api.servic AdminNebGoogleConfigComponent, AdminNebImgurConfigComponent, ConfigSimpleBotComponent, + AdminIrcBridgeNetworksComponent, ] }) export class AppModule { diff --git a/web/app/shared/services/admin/admin-irc-api.service.ts b/web/app/shared/services/admin/admin-irc-api.service.ts index cf7df20..ed47554 100644 --- a/web/app/shared/services/admin/admin-irc-api.service.ts +++ b/web/app/shared/services/admin/admin-irc-api.service.ts @@ -25,4 +25,10 @@ export class AdminIrcApiService extends AuthedApi { public newSelfhosted(provisionUrl: string): Promise { return this.authedPost("/api/v1/dimension/admin/irc/new/selfhosted", {provisionUrl: provisionUrl}).map(r => r.json()).toPromise(); } + + public setNetworkEnabled(bridgeId: number, networkId: string, isEnabled: boolean): Promise { + return this.authedPost("/api/v1/dimension/admin/irc/" + bridgeId + "/network/" + networkId + "/enabled", { + isEnabled: isEnabled, + }).map(r => r.json()).toPromise(); + } }