mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-08-31 14:12:08 +00:00
Early support for managing bots in the room
Known drawbacks: * Cannot remove bots * Cannot use upstream neb instances
This commit is contained in:
parent
dcda2fa46e
commit
947ecd43cd
@ -5,6 +5,7 @@ import { Cache, CACHE_INTEGRATIONS } from "../../MemoryCache";
|
|||||||
import { Integration } from "../../integrations/Integration";
|
import { Integration } from "../../integrations/Integration";
|
||||||
import { ApiError } from "../ApiError";
|
import { ApiError } from "../ApiError";
|
||||||
import { WidgetStore } from "../../db/WidgetStore";
|
import { WidgetStore } from "../../db/WidgetStore";
|
||||||
|
import { NebStore } from "../../db/NebStore";
|
||||||
|
|
||||||
export interface IntegrationsResponse {
|
export interface IntegrationsResponse {
|
||||||
widgets: Widget[],
|
widgets: Widget[],
|
||||||
@ -14,14 +15,18 @@ export interface IntegrationsResponse {
|
|||||||
export class DimensionIntegrationsService {
|
export class DimensionIntegrationsService {
|
||||||
|
|
||||||
public static async getIntegrations(isEnabledCheck?: boolean): Promise<IntegrationsResponse> {
|
public static async getIntegrations(isEnabledCheck?: boolean): Promise<IntegrationsResponse> {
|
||||||
const cachedWidgets = Cache.for(CACHE_INTEGRATIONS).get("integrations_" + isEnabledCheck);
|
const cachedIntegrations = Cache.for(CACHE_INTEGRATIONS).get("integrations_" + isEnabledCheck);
|
||||||
if (cachedWidgets) {
|
if (cachedIntegrations) {
|
||||||
return {widgets: cachedWidgets};
|
return cachedIntegrations;
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgets = await WidgetStore.listAll(isEnabledCheck);
|
const integrations = {
|
||||||
Cache.for(CACHE_INTEGRATIONS).put("integrations_" + isEnabledCheck, widgets);
|
widgets: await WidgetStore.listAll(isEnabledCheck),
|
||||||
return {widgets: widgets};
|
bots: await NebStore.listSimpleBots(), // No enabled check - managed internally
|
||||||
|
};
|
||||||
|
|
||||||
|
Cache.for(CACHE_INTEGRATIONS).put("integrations_" + isEnabledCheck, integrations);
|
||||||
|
return integrations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
@ -9,6 +9,7 @@ import NebBotUser from "./models/NebBotUser";
|
|||||||
import NebNotificationUser from "./models/NebNotificationUser";
|
import NebNotificationUser from "./models/NebNotificationUser";
|
||||||
import { AppserviceStore } from "./AppserviceStore";
|
import { AppserviceStore } from "./AppserviceStore";
|
||||||
import config from "../config";
|
import config from "../config";
|
||||||
|
import { SimpleBot } from "../integrations/SimpleBot";
|
||||||
|
|
||||||
export interface SupportedIntegration {
|
export interface SupportedIntegration {
|
||||||
type: string;
|
type: string;
|
||||||
@ -32,16 +33,19 @@ export class NebStore {
|
|||||||
name: "Echo",
|
name: "Echo",
|
||||||
avatarUrl: "/img/avatars/echo.png", // TODO: Make this image
|
avatarUrl: "/img/avatars/echo.png", // TODO: Make this image
|
||||||
description: "Repeats text given to it from !echo",
|
description: "Repeats text given to it from !echo",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
"giphy": {
|
"giphy": {
|
||||||
name: "Giphy",
|
name: "Giphy",
|
||||||
avatarUrl: "/img/avatars/giphy.png",
|
avatarUrl: "/img/avatars/giphy.png",
|
||||||
description: "Posts a GIF from Giphy using !giphy <query>",
|
description: "Posts a GIF from Giphy using !giphy <query>",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
"guggy": {
|
"guggy": {
|
||||||
name: "Guggy",
|
name: "Guggy",
|
||||||
avatarUrl: "/img/avatars/guggy.png",
|
avatarUrl: "/img/avatars/guggy.png",
|
||||||
description: "Send a reaction GIF using !guggy <query>",
|
description: "Send a reaction GIF using !guggy <query>",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
// TODO: Support Github
|
// TODO: Support Github
|
||||||
// "github": {
|
// "github": {
|
||||||
@ -53,11 +57,13 @@ export class NebStore {
|
|||||||
name: "Google",
|
name: "Google",
|
||||||
avatarUrl: "/img/avatars/google.png",
|
avatarUrl: "/img/avatars/google.png",
|
||||||
description: "Searches Google Images using !google image <query>",
|
description: "Searches Google Images using !google image <query>",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
"imgur": {
|
"imgur": {
|
||||||
name: "Imgur",
|
name: "Imgur",
|
||||||
avatarUrl: "/img/avatars/imgur.png",
|
avatarUrl: "/img/avatars/imgur.png",
|
||||||
description: "Searches and posts images from Imgur using !imgur <query>",
|
description: "Searches and posts images from Imgur using !imgur <query>",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
// TODO: Support JIRA
|
// TODO: Support JIRA
|
||||||
// "jira": {
|
// "jira": {
|
||||||
@ -79,9 +85,34 @@ export class NebStore {
|
|||||||
name: "Wikipedia",
|
name: "Wikipedia",
|
||||||
avatarUrl: "/img/avatars/wikipedia.png",
|
avatarUrl: "/img/avatars/wikipedia.png",
|
||||||
description: "Searches wikipedia using !wikipedia <query>",
|
description: "Searches wikipedia using !wikipedia <query>",
|
||||||
|
simple: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static async listSimpleBots(): Promise<SimpleBot[]> {
|
||||||
|
const configs = await NebStore.getAllConfigs();
|
||||||
|
const integrations: { integration: NebIntegration, userId: string }[] = [];
|
||||||
|
const hasTypes: string[] = [];
|
||||||
|
|
||||||
|
for (const config of configs) {
|
||||||
|
for (const integration of config.dbIntegrations) {
|
||||||
|
if (!integration.isEnabled) continue;
|
||||||
|
|
||||||
|
const metadata = NebStore.INTEGRATIONS[integration.type];
|
||||||
|
if (!metadata || !metadata.simple) continue;
|
||||||
|
if (hasTypes.indexOf(integration.type) !== -1) continue;
|
||||||
|
|
||||||
|
// TODO: Handle case of upstream bots
|
||||||
|
const user = await NebStore.getOrCreateBotUser(config.id, integration.type);
|
||||||
|
|
||||||
|
integrations.push({integration: integration, userId: user.appserviceUserId});
|
||||||
|
hasTypes.push(integration.type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return integrations.map(i => new SimpleBot(i.integration, i.userId));
|
||||||
|
}
|
||||||
|
|
||||||
public static async getAllConfigs(): Promise<NebConfig[]> {
|
public static async getAllConfigs(): Promise<NebConfig[]> {
|
||||||
const configs = await NebConfiguration.findAll();
|
const configs = await NebConfiguration.findAll();
|
||||||
return Promise.all((configs || []).map(c => NebStore.getConfig(c.id)));
|
return Promise.all((configs || []).map(c => NebStore.getConfig(c.id)));
|
||||||
|
@ -25,7 +25,7 @@ export class Integration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IntegrationRequirement {
|
export interface IntegrationRequirement {
|
||||||
condition: "publicRoom" | "canSendEventTypes";
|
condition: "publicRoom" | "canSendEventTypes" | "userInRoom";
|
||||||
argument: any;
|
argument: any;
|
||||||
|
|
||||||
// For publicRoom this is true or false (boolean)
|
// For publicRoom this is true or false (boolean)
|
||||||
|
13
src/integrations/SimpleBot.ts
Normal file
13
src/integrations/SimpleBot.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Integration } from "./Integration";
|
||||||
|
import NebIntegration from "../db/models/NebIntegration";
|
||||||
|
|
||||||
|
export class SimpleBot extends Integration {
|
||||||
|
constructor(bot: NebIntegration, public userId: string) {
|
||||||
|
super(bot);
|
||||||
|
this.category = "bot";
|
||||||
|
this.requirements = [];
|
||||||
|
|
||||||
|
// We're going to go ahead and claim that none of the bots are supported in e2e rooms
|
||||||
|
this.isEncryptionSupported = false;
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ export class NebConfig {
|
|||||||
public appserviceId?: string;
|
public appserviceId?: string;
|
||||||
public upstreamId?: number;
|
public upstreamId?: number;
|
||||||
public integrations: Integration[];
|
public integrations: Integration[];
|
||||||
|
public dbIntegrations: NebIntegration[];
|
||||||
|
|
||||||
public constructor(config: NebConfiguration, integrations: NebIntegration[]) {
|
public constructor(config: NebConfiguration, integrations: NebIntegration[]) {
|
||||||
this.id = config.id;
|
this.id = config.id;
|
||||||
@ -15,5 +16,6 @@ export class NebConfig {
|
|||||||
this.appserviceId = config.appserviceId;
|
this.appserviceId = config.appserviceId;
|
||||||
this.upstreamId = config.upstreamId;
|
this.upstreamId = config.upstreamId;
|
||||||
this.integrations = integrations.map(i => new Integration(i));
|
this.integrations = integrations.map(i => new Integration(i));
|
||||||
|
this.dbIntegrations = integrations;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router";
|
|||||||
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import { ScalarServerApiService } from "../../shared/services/scalar/scalar-server-api.service";
|
import { ScalarServerApiService } from "../../shared/services/scalar/scalar-server-api.service";
|
||||||
import { FE_Integration, FE_IntegrationRequirement } from "../../shared/models/integration";
|
import { FE_Integration, FE_IntegrationRequirement, FE_SimpleBot } from "../../shared/models/integration";
|
||||||
import { IntegrationsRegistry } from "../../shared/registry/integrations.registry";
|
import { IntegrationsRegistry } from "../../shared/registry/integrations.registry";
|
||||||
import { SessionStorage } from "../../shared/SessionStorage";
|
import { SessionStorage } from "../../shared/SessionStorage";
|
||||||
import { AdminApiService } from "../../shared/services/admin/admin-api.service";
|
import { AdminApiService } from "../../shared/services/admin/admin-api.service";
|
||||||
@ -129,13 +129,15 @@ export class RiotHomeComponent {
|
|||||||
|
|
||||||
if (integration.category === "bot") {
|
if (integration.category === "bot") {
|
||||||
// It's a bot
|
// It's a bot
|
||||||
|
const bot = <FE_SimpleBot>integration;
|
||||||
// TODO: "Are you sure?" dialog
|
// TODO: "Are you sure?" dialog
|
||||||
|
|
||||||
// let promise = null;
|
let promise:Promise<any> = Promise.resolve();
|
||||||
const promise = Promise.resolve();
|
if (!integration._inRoom) {
|
||||||
// if (!integration._inRoom) {
|
promise = this.scalar.inviteUser(this.roomId, bot.userId);
|
||||||
// promise = this.scalar.inviteUser(this.roomId, integration.userId);
|
}
|
||||||
// } else promise = this.api.removeIntegration(this.roomId, integration.type, integration.integrationType, this.scalarToken);
|
// TODO: Handle removal of bots
|
||||||
|
// else promise = this.api.removeIntegration(this.roomId, integration.type, integration.integrationType, this.scalarToken);
|
||||||
// We set this ahead of the promise for debouncing
|
// We set this ahead of the promise for debouncing
|
||||||
|
|
||||||
integration._inRoom = !integration._inRoom;
|
integration._inRoom = !integration._inRoom;
|
||||||
@ -228,11 +230,16 @@ export class RiotHomeComponent {
|
|||||||
console.log("Failed to find integration component for category=" + category + " type=" + type);
|
console.log("Failed to find integration component for category=" + category + " type=" + type);
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateIntegrationState(integration: FE_Integration) {
|
private async updateIntegrationState(integration: FE_Integration) {
|
||||||
if (!integration.requirements) return;
|
if (!integration.requirements) return;
|
||||||
|
|
||||||
let promises = integration.requirements.map(r => this.checkRequirement(r));
|
let promises = integration.requirements.map(r => this.checkRequirement(r));
|
||||||
|
|
||||||
|
if (integration.category === "bot") {
|
||||||
|
const state = await this.scalar.getMembershipState(this.roomId, (<FE_SimpleBot>integration).userId);
|
||||||
|
integration._inRoom = ["join", "invite"].indexOf(state.response.membership) !== -1;
|
||||||
|
}
|
||||||
|
|
||||||
return Promise.all(promises).then(() => {
|
return Promise.all(promises).then(() => {
|
||||||
integration._isSupported = true;
|
integration._isSupported = true;
|
||||||
integration._notSupportedReason = null;
|
integration._notSupportedReason = null;
|
||||||
|
@ -16,6 +16,10 @@ export interface FE_Integration {
|
|||||||
_notSupportedReason: string;
|
_notSupportedReason: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FE_SimpleBot extends FE_Integration {
|
||||||
|
userId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FE_Widget extends FE_Integration {
|
export interface FE_Widget extends FE_Integration {
|
||||||
options: any;
|
options: any;
|
||||||
}
|
}
|
||||||
|
BIN
web/public/img/avatars/echo.png
Normal file
BIN
web/public/img/avatars/echo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Loading…
Reference in New Issue
Block a user