mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-10-01 05:05:53 +00:00
parent
1233be85e9
commit
18597db540
@ -1,4 +1,4 @@
|
||||
import { DELETE, GET, Path, PathParam, QueryParam } from "typescript-rest";
|
||||
import { DELETE, GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
|
||||
import { ScalarService } from "../scalar/ScalarService";
|
||||
import { Widget } from "../../integrations/Widget";
|
||||
import { Cache, CACHE_INTEGRATIONS } from "../../MemoryCache";
|
||||
@ -67,6 +67,18 @@ export class DimensionIntegrationsService {
|
||||
else throw new ApiError(400, "Unrecognized category");
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("room/:roomId/integrations/:category/:type/config")
|
||||
public async setIntegrationConfigurationInRoom(@QueryParam("scalar_token") scalarToken: string, @PathParam("roomId") roomId: string, @PathParam("category") category: string, @PathParam("type") integrationType: string, newConfig: any): Promise<any> {
|
||||
const userId = await ScalarService.getTokenOwner(scalarToken);
|
||||
|
||||
if (category === "complex-bot") await NebStore.setComplexBotConfig(userId, integrationType, roomId, newConfig);
|
||||
else throw new ApiError(400, "Unrecognized category");
|
||||
|
||||
Cache.for(CACHE_INTEGRATIONS).clear(); // TODO: Improve which cache we invalidate
|
||||
return {}; // 200 OK
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("room/:roomId/integrations/:category/:type")
|
||||
public async removeIntegrationInRoom(@QueryParam("scalar_token") scalarToken: string, @PathParam("roomId") roomId: string, @PathParam("category") category: string, @PathParam("type") integrationType: string): Promise<any> {
|
||||
@ -74,8 +86,10 @@ export class DimensionIntegrationsService {
|
||||
|
||||
if (category === "widget") throw new ApiError(400, "Widgets should be removed client-side");
|
||||
else if (category === "bot") await NebStore.removeSimpleBot(integrationType, roomId, userId);
|
||||
else if (category === "complex-bot") throw new ApiError(400, "Complex bots should be removed automatically");
|
||||
else throw new ApiError(400, "Unrecognized category");
|
||||
|
||||
Cache.for(CACHE_INTEGRATIONS).clear(); // TODO: Improve which cache we invalidate
|
||||
return {}; // 200 OK
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import NebConfiguration from "./models/NebConfiguration";
|
||||
import NebIntegration from "./models/NebIntegration";
|
||||
import NebBotUser from "./models/NebBotUser";
|
||||
import NebNotificationUser from "./models/NebNotificationUser";
|
||||
import NebIntegrationConfig from "./models/NebIntegrationConfig";
|
||||
|
||||
class _DimensionStore {
|
||||
private sequelize: Sequelize;
|
||||
@ -37,6 +38,7 @@ class _DimensionStore {
|
||||
NebIntegration,
|
||||
NebBotUser,
|
||||
NebNotificationUser,
|
||||
NebIntegrationConfig,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -137,13 +137,22 @@ export class NebStore {
|
||||
const rawIntegrations = await NebStore.listEnabledNebComplexBots();
|
||||
return Promise.all(rawIntegrations.map(async i => {
|
||||
const proxy = new NebProxy(i.neb, requestingUserId);
|
||||
const notifUserId = await proxy.getNotificationUserId(i.integration, roomId, requestingUserId);
|
||||
const notifUserId = await proxy.getNotificationUserId(i.integration, roomId);
|
||||
const botUserId = null; // TODO: For github
|
||||
// TODO: Get configuration
|
||||
return new ComplexBot(i.integration, notifUserId, botUserId);
|
||||
const botConfig = await proxy.getServiceConfiguration(i.integration, roomId);
|
||||
return new ComplexBot(i.integration, notifUserId, botUserId, botConfig);
|
||||
}));
|
||||
}
|
||||
|
||||
public static async setComplexBotConfig(requestingUserId: string, type: string, roomId: string, newConfig: any): Promise<any> {
|
||||
const rawIntegrations = await NebStore.listEnabledNebComplexBots();
|
||||
const integration = rawIntegrations.find(i => i.integration.type === type);
|
||||
if (!integration) throw new Error("Integration not found");
|
||||
|
||||
const proxy = new NebProxy(integration.neb, requestingUserId);
|
||||
return proxy.setServiceConfiguration(integration.integration, roomId, newConfig);
|
||||
}
|
||||
|
||||
public static async removeSimpleBot(type: string, roomId: string, requestingUserId: string): Promise<any> {
|
||||
const rawIntegrations = await NebStore.listEnabledNebSimpleBots();
|
||||
const integration = rawIntegrations.find(i => i.integration.type === type);
|
||||
|
22
src/db/migrations/20180326185545-AddNebIntegrationConfig.ts
Normal file
22
src/db/migrations/20180326185545-AddNebIntegrationConfig.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { QueryInterface } from "sequelize";
|
||||
import { DataType } from "sequelize-typescript";
|
||||
|
||||
export default {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return Promise.resolve()
|
||||
.then(() => queryInterface.createTable("dimension_neb_integration_config", {
|
||||
"id": {type: DataType.INTEGER, primaryKey: true, autoIncrement: true, allowNull: false},
|
||||
"integrationId": {
|
||||
type: DataType.INTEGER, allowNull: false,
|
||||
references: {model: "dimension_neb_integrations", key: "id"},
|
||||
onUpdate: "cascade", onDelete: "cascade",
|
||||
},
|
||||
"roomId": {type: DataType.STRING, allowNull: false},
|
||||
"jsonContent": {type: DataType.STRING, allowNull: false},
|
||||
}));
|
||||
},
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return Promise.resolve()
|
||||
.then(() => queryInterface.dropTable("dimension_neb_integration_config"));
|
||||
}
|
||||
}
|
24
src/db/models/NebIntegrationConfig.ts
Normal file
24
src/db/models/NebIntegrationConfig.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { AutoIncrement, Column, ForeignKey, Model, PrimaryKey, Table } from "sequelize-typescript";
|
||||
import NebIntegration from "./NebIntegration";
|
||||
|
||||
@Table({
|
||||
tableName: "dimension_neb_integration_config",
|
||||
underscoredAll: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebIntegrationConfig extends Model<NebIntegrationConfig> {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
id: number;
|
||||
|
||||
@Column
|
||||
@ForeignKey(() => NebIntegration)
|
||||
integrationId: string;
|
||||
|
||||
@Column
|
||||
roomId: string;
|
||||
|
||||
@Column
|
||||
jsonContent: string;
|
||||
}
|
@ -2,7 +2,7 @@ import { Integration } from "./Integration";
|
||||
import NebIntegration from "../db/models/NebIntegration";
|
||||
|
||||
export class ComplexBot extends Integration {
|
||||
constructor(bot: NebIntegration, public notificationUserId: string, public botUserId?: string) {
|
||||
constructor(bot: NebIntegration, public notificationUserId: string, public botUserId: string, public config: any) {
|
||||
super(bot);
|
||||
this.category = "complex-bot";
|
||||
this.requirements = [];
|
||||
@ -10,4 +10,12 @@ export class ComplexBot extends Integration {
|
||||
// Notification bots are technically supported in e2e rooms
|
||||
this.isEncryptionSupported = true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface RssBotConfiguration {
|
||||
feeds: {
|
||||
[url: string]: {
|
||||
addedByUserId: string;
|
||||
};
|
||||
};
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export interface ModularIntegrationInfoResponse {
|
||||
bot_user_id: string;
|
||||
integrations?: any[];
|
||||
}
|
@ -73,6 +73,7 @@ export class NebClient {
|
||||
reject(err);
|
||||
} else if (res.statusCode !== 200) {
|
||||
LogService.error("NebClient", "Got status code " + res.statusCode + " while performing request");
|
||||
LogService.error("NebClient", res.body);
|
||||
reject(new Error("Request error"));
|
||||
} else {
|
||||
resolve(res.body);
|
||||
|
@ -9,6 +9,8 @@ import { NebClient } from "./NebClient";
|
||||
import { ModularIntegrationInfoResponse } from "../models/ModularResponses";
|
||||
import { AppserviceStore } from "../db/AppserviceStore";
|
||||
import { MatrixAppserviceClient } from "../matrix/MatrixAppserviceClient";
|
||||
import NebIntegrationConfig from "../db/models/NebIntegrationConfig";
|
||||
import { RssBotConfiguration } from "../integrations/ComplexBot";
|
||||
|
||||
export class NebProxy {
|
||||
constructor(private neb: NebConfig, private requestingUserId: string) {
|
||||
@ -31,7 +33,7 @@ export class NebProxy {
|
||||
}
|
||||
}
|
||||
|
||||
public async getNotificationUserId(integration: NebIntegration, inRoomId: string, forUserId: string): Promise<string> {
|
||||
public async getNotificationUserId(integration: NebIntegration, inRoomId: string): Promise<string> {
|
||||
if (integration.nebId !== this.neb.id) throw new Error("Integration is not for this NEB proxy");
|
||||
|
||||
if (this.neb.upstreamId) {
|
||||
@ -45,13 +47,133 @@ export class NebProxy {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return (await NebStore.getOrCreateNotificationUser(this.neb.id, integration.type, forUserId)).appserviceUserId;
|
||||
return (await NebStore.getOrCreateNotificationUser(this.neb.id, integration.type, this.requestingUserId)).appserviceUserId;
|
||||
}
|
||||
}
|
||||
|
||||
// public async getComplexBotConfiguration(integration: NebIntegration, roomId: string): Promise<any> {
|
||||
//
|
||||
// }
|
||||
public async getServiceConfiguration(integration: NebIntegration, inRoomId: string): Promise<any> {
|
||||
if (integration.nebId !== this.neb.id) throw new Error("Integration is not for this NEB proxy");
|
||||
|
||||
if (this.neb.upstreamId) {
|
||||
// TODO: Verify
|
||||
try {
|
||||
const response = await this.doUpstreamRequest<ModularIntegrationInfoResponse>("/integrations/" + NebClient.getNebType(integration.type), {
|
||||
room_id: inRoomId,
|
||||
});
|
||||
|
||||
if (integration.type === "rss") return this.parseUpstreamRssConfiguration(response.integrations);
|
||||
else return {};
|
||||
} catch (err) {
|
||||
LogService.error("NebProxy", err);
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
const serviceConfig = await NebIntegrationConfig.findOne({
|
||||
where: {
|
||||
integrationId: integration.id,
|
||||
roomId: inRoomId,
|
||||
},
|
||||
});
|
||||
return serviceConfig ? JSON.parse(serviceConfig.jsonContent) : {};
|
||||
}
|
||||
}
|
||||
|
||||
public async setServiceConfiguration(integration: NebIntegration, inRoomId: string, newConfig: any): Promise<any> {
|
||||
if (integration.nebId !== this.neb.id) throw new Error("Integration is not for this NEB proxy");
|
||||
|
||||
if (!this.neb.upstreamId) {
|
||||
const serviceConfig = await NebIntegrationConfig.findOne({
|
||||
where: {
|
||||
integrationId: integration.id,
|
||||
roomId: inRoomId,
|
||||
},
|
||||
});
|
||||
if (serviceConfig) {
|
||||
serviceConfig.jsonContent = JSON.stringify(newConfig);
|
||||
await serviceConfig.save();
|
||||
} else {
|
||||
await NebIntegrationConfig.create({
|
||||
integrationId: integration.id,
|
||||
roomId: inRoomId,
|
||||
jsonContent: JSON.stringify(newConfig),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (integration.type === "rss") await this.updateRssConfiguration(inRoomId, newConfig);
|
||||
else throw new Error("Cannot update go-neb: unrecognized type");
|
||||
}
|
||||
|
||||
private parseUpstreamRssConfiguration(integrations: any[]): any {
|
||||
if (!integrations) return {};
|
||||
|
||||
const result: RssBotConfiguration = {feeds: {}};
|
||||
for (const integration of integrations) {
|
||||
const userId = integration.user_id;
|
||||
const feeds = integration.config ? integration.config.feeds : {};
|
||||
if (!userId || !feeds) continue;
|
||||
|
||||
const urls = Object.keys(feeds);
|
||||
urls.forEach(u => result.feeds[u] = {addedByUserId: userId});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async updateRssConfiguration(roomId: string, newOpts: RssBotConfiguration): Promise<any> {
|
||||
const feedUrls = Object.keys(newOpts.feeds).filter(f => newOpts.feeds[f].addedByUserId === this.requestingUserId);
|
||||
const newConfig = {feeds: {}};
|
||||
let currentConfig = {feeds: {}};
|
||||
|
||||
if (this.neb.upstreamId) {
|
||||
const response = await this.doUpstreamRequest<ModularIntegrationInfoResponse>("/integrations/rssbot", {room_id: roomId});
|
||||
currentConfig = await this.parseUpstreamRssConfiguration(response.integrations);
|
||||
} else {
|
||||
const client = new NebClient(this.neb);
|
||||
const notifUser = await NebStore.getOrCreateNotificationUser(this.neb.id, "rss", this.requestingUserId);
|
||||
currentConfig = await client.getServiceConfig(notifUser.serviceId);
|
||||
|
||||
if (feedUrls.length === 0) {
|
||||
const client = new MatrixAppserviceClient(await AppserviceStore.getAppservice(this.neb.appserviceId));
|
||||
await client.leaveRoom(notifUser.appserviceUserId, roomId);
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentConfig || !currentConfig.feeds) currentConfig = {feeds: {}};
|
||||
|
||||
const allUrls = feedUrls.concat(Object.keys(currentConfig.feeds));
|
||||
for (const feedUrl of allUrls) {
|
||||
let feed = currentConfig.feeds[feedUrl];
|
||||
if (!feed) feed = {poll_interval_mins: 60, rooms: []};
|
||||
|
||||
const hasRoom = feed.rooms.indexOf(roomId) !== -1;
|
||||
const isEnabled = feedUrls.indexOf(feedUrl) !== -1;
|
||||
|
||||
if (hasRoom && !isEnabled) {
|
||||
feed.rooms.splice(feed.rooms.indexOf(roomId), 1);
|
||||
} else if (!hasRoom && isEnabled) {
|
||||
feed.rooms.push(roomId);
|
||||
}
|
||||
|
||||
if (feed.rooms.length > 0) {
|
||||
newConfig.feeds[feedUrl] = {
|
||||
poll_interval_mins: feed.poll_interval_mins,
|
||||
rooms: feed.rooms,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (this.neb.upstreamId) {
|
||||
await this.doUpstreamRequest<ModularIntegrationInfoResponse>("/integrations/rssbot/configureService", {
|
||||
room_id: roomId,
|
||||
feeds: newConfig.feeds,
|
||||
});
|
||||
} else {
|
||||
const client = new NebClient(this.neb);
|
||||
const notifUser = await NebStore.getOrCreateNotificationUser(this.neb.id, "rss", this.requestingUserId);
|
||||
await client.setServiceConfig(notifUser.serviceId, notifUser.appserviceUserId, "rssbot", newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
public async removeBotFromRoom(integration: NebIntegration, roomId: string): Promise<any> {
|
||||
if (integration.nebId !== this.neb.id) throw new Error("Integration is not for this NEB proxy");
|
||||
|
@ -5,6 +5,7 @@ import { Subscription } from "rxjs/Subscription";
|
||||
import { IntegrationsApiService } from "../../shared/services/integrations/integrations-api.service";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { ServiceLocator } from "../../shared/registry/locator.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
||||
|
||||
export class ComplexBotComponent<T> implements OnInit, OnDestroy {
|
||||
|
||||
@ -12,14 +13,14 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
|
||||
public isUpdating = false;
|
||||
public bot: FE_ComplexBot<T>;
|
||||
public newConfig: T;
|
||||
|
||||
private roomId: string;
|
||||
public roomId: string;
|
||||
|
||||
private routeQuerySubscription: Subscription;
|
||||
|
||||
protected toaster = ServiceLocator.injector.get(ToasterService);
|
||||
protected integrationsApi = ServiceLocator.injector.get(IntegrationsApiService);
|
||||
protected route = ServiceLocator.injector.get(ActivatedRoute);
|
||||
protected scalarClientApi = ServiceLocator.injector.get(ScalarClientApiService);
|
||||
|
||||
constructor(private integrationType: string) {
|
||||
this.isLoading = true;
|
||||
@ -45,10 +46,25 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
|
||||
|
||||
this.integrationsApi.getIntegrationInRoom("complex-bot", this.integrationType, this.roomId).then(i => {
|
||||
this.bot = <FE_ComplexBot<T>>i;
|
||||
this.newConfig = JSON.parse(JSON.stringify(this.bot.config));
|
||||
this.isLoading = false;
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
this.toaster.pop("error", "Failed to load configuration");
|
||||
});
|
||||
}
|
||||
|
||||
public save(): void {
|
||||
this.isUpdating = true;
|
||||
this.integrationsApi.setIntegrationConfiguration("complex-bot", this.integrationType, this.roomId, this.newConfig).then(() => {
|
||||
this.toaster.pop("success", "Configuration updated");
|
||||
this.bot.config = this.newConfig;
|
||||
this.newConfig = JSON.parse(JSON.stringify(this.bot.config));
|
||||
this.isUpdating = false;
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
this.toaster.pop("error", "Error updating configuration");
|
||||
this.isUpdating = false;
|
||||
});
|
||||
}
|
||||
}
|
@ -2,20 +2,5 @@
|
||||
<my-spinner></my-spinner>
|
||||
</div>
|
||||
<div *ngIf="!botComponent.isLoading">
|
||||
<my-ibox>
|
||||
<h5 class="my-ibox-title">
|
||||
{{ botComponent.bot.displayName }} configuration
|
||||
</h5>
|
||||
<div class="my-ibox-content">
|
||||
<form (submit)="botComponent.save()" novalidate name="saveForm">
|
||||
<ng-container *ngTemplateOutlet="botParamsTemplate"></ng-container>
|
||||
|
||||
<div style="margin-top: 25px">
|
||||
<button type="submit" class="btn btn-sm btn-success" [disabled]="botComponent.isUpdating">
|
||||
<i class="far fa-save"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</my-ibox>
|
||||
<ng-container *ngTemplateOutlet="botParamsTemplate"></ng-container>
|
||||
</div>
|
@ -1,5 +1,58 @@
|
||||
<my-complex-bot-config [botComponent]="this">
|
||||
<ng-template #botParamsTemplate>
|
||||
<p>{{ bot | json }}</p>
|
||||
<my-ibox>
|
||||
<h5 class="my-ibox-title">
|
||||
Feeds
|
||||
</h5>
|
||||
<div class="my-ibox-content">
|
||||
<form (submit)="interceptSave()" novalidate name="saveForm">
|
||||
<table class="table table-striped table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>URL</th>
|
||||
<th>Added by</th>
|
||||
<th class="actions-col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let feed of getFeeds()">
|
||||
<td>{{ feed.url }}</td>
|
||||
<td>{{ feed.addedByUserId }}</td>
|
||||
<td class="actions-col">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger"
|
||||
[disabled]="isUpdating || !feed.isSelf"
|
||||
(click)="removeFeed(feed)">
|
||||
<i class="far fa-trash-alt"></i> Remove
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control"
|
||||
[(ngModel)]="newFeedUrl"
|
||||
placeholder="https://example.org/feed.atom"
|
||||
name="newFeedUrl"
|
||||
title="New feed URL" />
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-outline-success"
|
||||
[disabled]="isUpdating"
|
||||
(click)="addFeed()">
|
||||
<i class="fa fa-plus"></i> Add
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div style="margin-top: 25px">
|
||||
<button type="submit" class="btn btn-sm btn-primary" [disabled]="isUpdating">
|
||||
<i class="far fa-save"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</my-ibox>
|
||||
</ng-template>
|
||||
</my-complex-bot-config>
|
@ -0,0 +1,4 @@
|
||||
.actions-col {
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
}
|
@ -1,18 +1,66 @@
|
||||
import { ComplexBotComponent } from "../complex-bot.component";
|
||||
import { Component } from "@angular/core";
|
||||
import { SessionStorage } from "../../../shared/SessionStorage";
|
||||
|
||||
interface RssConfig {
|
||||
feeds: {
|
||||
[feedUrl: string]: {}; // No options currently
|
||||
[feedUrl: string]: {
|
||||
addedByUserId: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
interface LocalFeed {
|
||||
url: string;
|
||||
addedByUserId: string;
|
||||
isSelf: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "rss.complex-bot.component.html",
|
||||
styleUrls: ["rss.complex-bot.component.scss"],
|
||||
})
|
||||
export class RssComplexBotConfigComponent extends ComplexBotComponent<RssConfig> {
|
||||
|
||||
public newFeedUrl = "";
|
||||
|
||||
constructor() {
|
||||
super("rss");
|
||||
}
|
||||
|
||||
public addFeed(): void {
|
||||
if (!this.newFeedUrl.trim()) {
|
||||
this.toaster.pop('warning', 'Please enter a feed URL');
|
||||
return;
|
||||
}
|
||||
|
||||
this.newConfig.feeds[this.newFeedUrl] = {addedByUserId: SessionStorage.userId};
|
||||
this.newFeedUrl = "";
|
||||
}
|
||||
|
||||
public getFeeds(): LocalFeed[] {
|
||||
if (!this.newConfig.feeds) this.newConfig.feeds = {};
|
||||
return Object.keys(this.newConfig.feeds).map(url => {
|
||||
return {
|
||||
url: url,
|
||||
addedByUserId: this.newConfig.feeds[url].addedByUserId,
|
||||
isSelf: SessionStorage.userId === this.newConfig.feeds[url].addedByUserId,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
public removeFeed(feed: LocalFeed): void {
|
||||
delete this.newConfig.feeds[feed.url];
|
||||
}
|
||||
|
||||
public async interceptSave(): Promise<any> {
|
||||
const memberEvent = await this.scalarClientApi.getMembershipState(this.roomId, this.bot.notificationUserId);
|
||||
const isJoined = memberEvent && memberEvent.response && ["join", "invite"].indexOf(memberEvent.response.membership) !== -1;
|
||||
|
||||
if (!isJoined) {
|
||||
await this.scalarClientApi.inviteUser(this.roomId, this.bot.notificationUserId);
|
||||
}
|
||||
|
||||
super.save();
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@ export class IntegrationsApiService extends AuthedApi {
|
||||
return this.authedGet("/api/v1/dimension/integrations/room/" + roomId + "/integrations/" + category + "/" + type).map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public setIntegrationConfiguration(category: string, type: string, roomId: string, newConfig: any): Promise<any> {
|
||||
return this.authedPost("/api/v1/dimension/integrations/room/" + roomId + "/integrations/" + category + "/" + type + "/config", newConfig).map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public getWidget(type: string): Promise<FE_Widget> {
|
||||
return this.getIntegration("widget", type).then(i => <FE_Widget>i);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user