mirror of
https://github.com/turt2live/matrix-dimension.git
synced 2024-10-01 05:05:53 +00:00
Support configuring the upstream go-neb bots
This commit is contained in:
parent
5314bea52d
commit
8b3f6e37ce
@ -22,4 +22,26 @@ export class MemoryCache {
|
||||
public clear(): void {
|
||||
this.internalCache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _CacheManager {
|
||||
private caches: { [namespace: string]: MemoryCache } = {};
|
||||
|
||||
public for(namespace: string): MemoryCache {
|
||||
let cache = this.caches[namespace];
|
||||
if (!cache) {
|
||||
cache = this.caches[namespace] = new MemoryCache();
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
export const Cache = new _CacheManager();
|
||||
|
||||
export const CACHE_INTEGRATIONS = "integrations";
|
||||
export const CACHE_NEB = "neb";
|
||||
export const CACHE_UPSTREAM = "upstream";
|
||||
export const CACHE_SCALAR_ACCOUNTS = "scalar-accounts";
|
||||
export const CACHE_WIDGET_TITLES = "widget-titles";
|
||||
export const CACHE_FEDERATION = "federation";
|
@ -28,7 +28,7 @@ export class DimensionAdminService {
|
||||
}
|
||||
|
||||
public static validateAndGetAdminTokenOwner(scalarToken: string): Promise<string> {
|
||||
return ScalarService.getTokenOwner(scalarToken).then(userId => {
|
||||
return ScalarService.getTokenOwner(scalarToken, true).then(userId => {
|
||||
if (!DimensionAdminService.isAdmin(userId))
|
||||
throw new ApiError(401, {message: "You must be an administrator to use this API"});
|
||||
else return userId;
|
||||
|
@ -4,6 +4,7 @@ import { ApiError } from "../ApiError";
|
||||
import { DimensionAdminService } from "./DimensionAdminService";
|
||||
import { DimensionIntegrationsService, IntegrationsResponse } from "./DimensionIntegrationsService";
|
||||
import { WidgetStore } from "../../db/WidgetStore";
|
||||
import { CACHE_INTEGRATIONS, Cache } from "../../MemoryCache";
|
||||
|
||||
interface SetEnabledRequest {
|
||||
enabled: boolean;
|
||||
@ -23,7 +24,7 @@ export class DimensionIntegrationsAdminService {
|
||||
if (category === "widget") {
|
||||
return WidgetStore.setOptions(type, body.options);
|
||||
} else throw new ApiError(400, "Unrecongized category");
|
||||
}).then(() => DimensionIntegrationsService.clearIntegrationCache());
|
||||
}).then(() => Cache.for(CACHE_INTEGRATIONS).clear());
|
||||
}
|
||||
|
||||
@POST
|
||||
@ -33,7 +34,7 @@ export class DimensionIntegrationsAdminService {
|
||||
if (category === "widget") {
|
||||
return WidgetStore.setEnabled(type, body.enabled);
|
||||
} else throw new ApiError(400, "Unrecongized category");
|
||||
}).then(() => DimensionIntegrationsService.clearIntegrationCache());
|
||||
}).then(() => Cache.for(CACHE_INTEGRATIONS).clear());
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -2,7 +2,7 @@ import { GET, Path, PathParam, QueryParam } from "typescript-rest";
|
||||
import * as Promise from "bluebird";
|
||||
import { ScalarService } from "../scalar/ScalarService";
|
||||
import { Widget } from "../../integrations/Widget";
|
||||
import { MemoryCache } from "../../MemoryCache";
|
||||
import { CACHE_INTEGRATIONS, Cache } from "../../MemoryCache";
|
||||
import { Integration } from "../../integrations/Integration";
|
||||
import { ApiError } from "../ApiError";
|
||||
import { WidgetStore } from "../../db/WidgetStore";
|
||||
@ -14,14 +14,8 @@ export interface IntegrationsResponse {
|
||||
@Path("/api/v1/dimension/integrations")
|
||||
export class DimensionIntegrationsService {
|
||||
|
||||
private static integrationCache = new MemoryCache();
|
||||
|
||||
public static clearIntegrationCache() {
|
||||
DimensionIntegrationsService.integrationCache.clear();
|
||||
}
|
||||
|
||||
public static getIntegrations(isEnabledCheck?: boolean): Promise<IntegrationsResponse> {
|
||||
const cachedResponse = DimensionIntegrationsService.integrationCache.get("integrations_" + isEnabledCheck);
|
||||
const cachedResponse = Cache.for(CACHE_INTEGRATIONS).get("integrations_" + isEnabledCheck);
|
||||
if (cachedResponse) {
|
||||
return cachedResponse;
|
||||
}
|
||||
@ -33,7 +27,7 @@ export class DimensionIntegrationsService {
|
||||
.then(widgets => response.widgets = widgets)
|
||||
|
||||
// Cache and return response
|
||||
.then(() => DimensionIntegrationsService.integrationCache.put("integrations_" + isEnabledCheck, response))
|
||||
.then(() => Cache.for(CACHE_INTEGRATIONS).put("integrations_" + isEnabledCheck, response))
|
||||
.then(() => response);
|
||||
}
|
||||
|
||||
|
91
src/api/dimension/DimensionNebAdminService.ts
Normal file
91
src/api/dimension/DimensionNebAdminService.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import { GET, Path, PathParam, POST, QueryParam } from "typescript-rest";
|
||||
import * as Promise from "bluebird";
|
||||
import { DimensionAdminService } from "./DimensionAdminService";
|
||||
import { Cache, CACHE_NEB } from "../../MemoryCache";
|
||||
import { NebStore } from "../../db/NebStore";
|
||||
import { NebConfig } from "../../models/neb";
|
||||
import { LogService } from "matrix-js-snippets";
|
||||
import { ApiError } from "../ApiError";
|
||||
|
||||
interface CreateWithUpstream {
|
||||
upstreamId: number;
|
||||
}
|
||||
|
||||
interface CreateWithAppservice {
|
||||
appserviceId: string;
|
||||
adminUrl: string;
|
||||
}
|
||||
|
||||
interface SetEnabledRequest {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
|
||||
@Path("/api/v1/dimension/admin/neb")
|
||||
export class DimensionNebAdminService {
|
||||
|
||||
@GET
|
||||
@Path("all")
|
||||
public getNebConfigs(@QueryParam("scalar_token") scalarToken: string): Promise<NebConfig[]> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
const cachedConfigs = Cache.for(CACHE_NEB).get("configurations");
|
||||
if (cachedConfigs) return cachedConfigs;
|
||||
|
||||
return NebStore.getAllConfigs().then(configs => {
|
||||
Cache.for(CACHE_NEB).put("configurations", configs);
|
||||
return configs;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path(":id/config")
|
||||
public getNebConfig(@QueryParam("scalar_token") scalarToken: string, @PathParam("id") nebId: number): Promise<NebConfig> {
|
||||
return this.getNebConfigs(scalarToken).then(configs => {
|
||||
for (const config of configs) {
|
||||
if (config.id === nebId) return config;
|
||||
}
|
||||
|
||||
throw new ApiError(404, "Configuration not found");
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path(":id/integration/:type/enabled")
|
||||
public setIntegrationEnabled(@QueryParam("scalar_token") scalarToken: string, @PathParam("id") nebId: number, @PathParam("type") integrationType: string, request: SetEnabledRequest): Promise<any> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
return NebStore.getOrCreateIntegration(nebId, integrationType);
|
||||
}).then(integration => {
|
||||
integration.isEnabled = request.enabled;
|
||||
return integration.save();
|
||||
}).then(() => Cache.for(CACHE_NEB).clear());
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("new/upstream")
|
||||
public newConfigForUpstream(@QueryParam("scalar_token") scalarToken: string, request: CreateWithUpstream): Promise<NebConfig> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
return NebStore.createForUpstream(request.upstreamId).catch(err => {
|
||||
LogService.error("DimensionNebAdminService", err);
|
||||
throw new ApiError(500, "Error creating go-neb instance");
|
||||
});
|
||||
}).then(config => {
|
||||
Cache.for(CACHE_NEB).clear();
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("new/appservice")
|
||||
public newConfigForAppservice(@QueryParam("scalar_token") scalarToken: string, request: CreateWithAppservice): Promise<NebConfig> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
return NebStore.createForAppservice(request.appserviceId, request.adminUrl).catch(err => {
|
||||
LogService.error("DimensionNebAdminService", err);
|
||||
throw new ApiError(500, "Error creating go-neb instance");
|
||||
});
|
||||
}).then(config => {
|
||||
Cache.for(CACHE_NEB).clear();
|
||||
return config;
|
||||
});
|
||||
}
|
||||
}
|
65
src/api/dimension/DimensionUpstreamAdminService.ts
Normal file
65
src/api/dimension/DimensionUpstreamAdminService.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { GET, Path, POST, QueryParam } from "typescript-rest";
|
||||
import * as Promise from "bluebird";
|
||||
import { DimensionAdminService } from "./DimensionAdminService";
|
||||
import { Cache, CACHE_UPSTREAM } from "../../MemoryCache";
|
||||
import Upstream from "../../db/models/Upstream";
|
||||
|
||||
interface UpstreamRepsonse {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
scalarUrl: string;
|
||||
apiUrl: string;
|
||||
}
|
||||
|
||||
interface NewUpstreamRequest {
|
||||
name: string;
|
||||
type: string;
|
||||
scalarUrl: string;
|
||||
apiUrl: string;
|
||||
}
|
||||
|
||||
@Path("/api/v1/dimension/admin/upstreams")
|
||||
export class DimensionUpstreamAdminService {
|
||||
|
||||
@GET
|
||||
@Path("all")
|
||||
public getUpstreams(@QueryParam("scalar_token") scalarToken: string): Promise<UpstreamRepsonse[]> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
const cachedUpstreams = Cache.for(CACHE_UPSTREAM).get("upstreams");
|
||||
if (cachedUpstreams) return cachedUpstreams;
|
||||
return Upstream.findAll().then(upstreams => {
|
||||
const mapped = upstreams.map(this.mapUpstream);
|
||||
Cache.for(CACHE_UPSTREAM).put("upstreams", mapped);
|
||||
|
||||
return mapped;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("new")
|
||||
public createUpstream(@QueryParam("scalar_token") scalarToken: string, request: NewUpstreamRequest): Promise<UpstreamRepsonse> {
|
||||
return DimensionAdminService.validateAndGetAdminTokenOwner(scalarToken).then(_userId => {
|
||||
return Upstream.create({
|
||||
name: request.name,
|
||||
type: request.type,
|
||||
scalarUrl: request.scalarUrl,
|
||||
apiUrl: request.apiUrl,
|
||||
});
|
||||
}).then(upstream => {
|
||||
Cache.for(CACHE_UPSTREAM).clear();
|
||||
return this.mapUpstream(upstream);
|
||||
});
|
||||
}
|
||||
|
||||
private mapUpstream(upstream: Upstream): UpstreamRepsonse {
|
||||
return {
|
||||
id: upstream.id,
|
||||
name: upstream.name,
|
||||
type: upstream.type,
|
||||
scalarUrl: upstream.scalarUrl,
|
||||
apiUrl: upstream.apiUrl
|
||||
};
|
||||
}
|
||||
}
|
@ -10,7 +10,7 @@ import { ApiError } from "../ApiError";
|
||||
import * as randomString from "random-string";
|
||||
import { OpenId } from "../../models/OpenId";
|
||||
import { ScalarAccountResponse, ScalarRegisterResponse } from "../../models/ScalarResponses";
|
||||
import { MemoryCache } from "../../MemoryCache";
|
||||
import { Cache, CACHE_SCALAR_ACCOUNTS } from "../../MemoryCache";
|
||||
import { ScalarStore } from "../../db/ScalarStore";
|
||||
|
||||
interface RegisterRequest {
|
||||
@ -23,19 +23,13 @@ interface RegisterRequest {
|
||||
@Path("/api/v1/scalar")
|
||||
export class ScalarService {
|
||||
|
||||
private static accountCache = new MemoryCache();
|
||||
|
||||
public static clearAccountCache(): void {
|
||||
ScalarService.accountCache.clear();
|
||||
}
|
||||
|
||||
public static getTokenOwner(scalarToken: string): Promise<string> {
|
||||
const cachedUserId = ScalarService.accountCache.get(scalarToken);
|
||||
public static getTokenOwner(scalarToken: string, ignoreUpstreams?: boolean): Promise<string> {
|
||||
const cachedUserId = Cache.for(CACHE_SCALAR_ACCOUNTS).get(scalarToken);
|
||||
if (cachedUserId) return Promise.resolve(cachedUserId);
|
||||
|
||||
return ScalarStore.getTokenOwner(scalarToken).then(user => {
|
||||
return ScalarStore.getTokenOwner(scalarToken, ignoreUpstreams).then(user => {
|
||||
if (!user) return Promise.reject("Invalid token");
|
||||
ScalarService.accountCache.put(scalarToken, user.userId, 30 * 60 * 1000); // 30 minutes
|
||||
Cache.for(CACHE_SCALAR_ACCOUNTS).put(scalarToken, user.userId, 30 * 60 * 1000); // 30 minutes
|
||||
return Promise.resolve(user.userId);
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GET, Path, QueryParam } from "typescript-rest";
|
||||
import * as Promise from "bluebird";
|
||||
import { LogService } from "matrix-js-snippets";
|
||||
import { MemoryCache } from "../../MemoryCache";
|
||||
import { CACHE_WIDGET_TITLES, Cache } from "../../MemoryCache";
|
||||
import { MatrixLiteClient } from "../../matrix/MatrixLiteClient";
|
||||
import config from "../../config";
|
||||
import { ScalarService } from "./ScalarService";
|
||||
@ -22,10 +22,8 @@ interface UrlPreviewResponse {
|
||||
@Path("/api/v1/scalar/widgets")
|
||||
export class ScalarWidgetService {
|
||||
|
||||
private static urlCache = new MemoryCache();
|
||||
|
||||
private static getUrlTitle(url: string): Promise<UrlPreviewResponse> {
|
||||
const cachedResult = ScalarWidgetService.urlCache.get(url);
|
||||
const cachedResult = Cache.for(CACHE_WIDGET_TITLES).get(url);
|
||||
if (cachedResult) {
|
||||
cachedResult.cached_response = true;
|
||||
return Promise.resolve(cachedResult);
|
||||
@ -44,7 +42,7 @@ export class ScalarWidgetService {
|
||||
},
|
||||
error: {message: null},
|
||||
};
|
||||
ScalarWidgetService.urlCache.put(url, cachedItem, expirationTime);
|
||||
Cache.for(CACHE_WIDGET_TITLES).put(url, cachedItem, expirationTime);
|
||||
return cachedItem;
|
||||
}).catch(err => {
|
||||
LogService.error("ScalarWidgetService", "Error getting URL preview");
|
||||
|
179
src/db/NebStore.ts
Normal file
179
src/db/NebStore.ts
Normal file
@ -0,0 +1,179 @@
|
||||
import * as Promise from "bluebird";
|
||||
import { resolveIfExists } from "./DimensionStore";
|
||||
import { NebConfig } from "../models/neb";
|
||||
import NebConfiguration from "./models/NebConfiguration";
|
||||
import NebIntegration from "./models/NebIntegration";
|
||||
import Upstream from "./models/Upstream";
|
||||
import AppService from "./models/AppService";
|
||||
import { LogService } from "matrix-js-snippets";
|
||||
|
||||
export interface SupportedIntegration {
|
||||
type: string;
|
||||
name: string;
|
||||
avatarUrl: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export class NebStore {
|
||||
|
||||
private static INTEGRATIONS_MODULAR_SUPPORTED = ["giphy", "guggy", "github", "google", "imgur", "rss", "travisci", "wikipedia"];
|
||||
|
||||
private static INTEGRATIONS = {
|
||||
"circleci": {
|
||||
name: "Circle CI",
|
||||
avatarUrl: "/img/avatars/circleci.png",
|
||||
description: "Announces build results from Circle CI to the room.",
|
||||
},
|
||||
"echo": {
|
||||
name: "Echo",
|
||||
avatarUrl: "/img/avatars/echo.png", // TODO: Make this image
|
||||
description: "Repeats text given to it from !echo",
|
||||
},
|
||||
"giphy": {
|
||||
name: "Giphy",
|
||||
avatarUrl: "/img/avatars/giphy.png",
|
||||
description: "Posts a GIF from Giphy using !giphy <query>",
|
||||
},
|
||||
"guggy": {
|
||||
name: "Guggy",
|
||||
avatarUrl: "/img/avatars/guggy.png",
|
||||
description: "Send a reaction GIF using !guggy <query>",
|
||||
},
|
||||
"github": {
|
||||
name: "Github",
|
||||
avatarUrl: "/img/avatars/github.png",
|
||||
description: "Github issue management and announcements for a repository",
|
||||
},
|
||||
"google": {
|
||||
name: "Google",
|
||||
avatarUrl: "/img/avatars/google.png",
|
||||
description: "Searches Google Images using !google image <query>",
|
||||
},
|
||||
"imgur": {
|
||||
name: "Imgur",
|
||||
avatarUrl: "/img/avatars/imgur.png",
|
||||
description: "Searches and posts images from Imgur using !imgur <query>",
|
||||
},
|
||||
// TODO: Support JIRA
|
||||
// "jira": {
|
||||
// name: "Jira",
|
||||
// avatarUrl: "/img/avatars/jira.png",
|
||||
// description: "Jira issue management and announcements for a project",
|
||||
// },
|
||||
"rss": {
|
||||
name: "RSS",
|
||||
avatarUrl: "/img/avatars/rssbot.png",
|
||||
description: "Announces changes to RSS feeds in the room",
|
||||
},
|
||||
"travisci": {
|
||||
name: "Travis CI",
|
||||
avatarUrl: "/img/avatars/travisci.png",
|
||||
description: "Announces build results from Travis CI to the room",
|
||||
},
|
||||
"wikipedia": {
|
||||
name: "Wikipedia",
|
||||
avatarUrl: "/img/avatars/wikipedia.png",
|
||||
description: "Searches wikipedia using !wikipedia <query>",
|
||||
},
|
||||
};
|
||||
|
||||
public static getAllConfigs(): Promise<NebConfig[]> {
|
||||
return NebConfiguration.findAll().then(configs => {
|
||||
return Promise.all((configs || []).map(c => NebStore.getConfig(c.id)));
|
||||
});
|
||||
}
|
||||
|
||||
public static getConfig(id: number): Promise<NebConfig> {
|
||||
let nebConfig: NebConfiguration;
|
||||
return NebConfiguration.findByPrimary(id).then(resolveIfExists).then(conf => {
|
||||
nebConfig = conf;
|
||||
return NebIntegration.findAll({where: {nebId: id}});
|
||||
}).then(integrations => {
|
||||
return NebStore.getCompleteIntegrations(nebConfig, integrations);
|
||||
}).then(integrations => {
|
||||
return new NebConfig(nebConfig, integrations);
|
||||
});
|
||||
}
|
||||
|
||||
public static createForUpstream(upstreamId: number): Promise<NebConfig> {
|
||||
return Upstream.findByPrimary(upstreamId).then(resolveIfExists).then(upstream => {
|
||||
return NebConfiguration.create({
|
||||
upstreamId: upstream.id,
|
||||
});
|
||||
}).then(config => {
|
||||
return NebStore.getConfig(config.id);
|
||||
});
|
||||
}
|
||||
|
||||
public static createForAppservice(appserviceId: string, adminUrl: string): Promise<NebConfig> {
|
||||
return AppService.findByPrimary(appserviceId).then(resolveIfExists).then(appservice => {
|
||||
return NebConfiguration.create({
|
||||
appserviceId: appservice.id,
|
||||
adminUrl: adminUrl,
|
||||
});
|
||||
}).then(config => {
|
||||
return NebStore.getConfig(config.id);
|
||||
});
|
||||
}
|
||||
|
||||
public static getOrCreateIntegration(configurationId: number, integrationType: string): Promise<NebIntegration> {
|
||||
if (!NebStore.INTEGRATIONS[integrationType]) return Promise.reject(new Error("Integration not supported"));
|
||||
|
||||
return NebConfiguration.findByPrimary(configurationId).then(resolveIfExists).then(config => {
|
||||
return NebIntegration.findOne({where: {nebId: config.id, type: integrationType}});
|
||||
}).then(integration => {
|
||||
if (!integration) {
|
||||
LogService.info("NebStore", "Creating integration " + integrationType + " for NEB " + configurationId);
|
||||
return NebIntegration.create({
|
||||
type: integrationType,
|
||||
name: NebStore.INTEGRATIONS[integrationType].name,
|
||||
avatarUrl: NebStore.INTEGRATIONS[integrationType].avatarUrl,
|
||||
description: NebStore.INTEGRATIONS[integrationType].description,
|
||||
isEnabled: false,
|
||||
isPublic: true,
|
||||
nebId: configurationId,
|
||||
});
|
||||
} else return Promise.resolve(integration);
|
||||
});
|
||||
}
|
||||
|
||||
public static getCompleteIntegrations(nebConfig: NebConfiguration, knownIntegrations: NebIntegration[]): Promise<NebIntegration[]> {
|
||||
const supported = NebStore.getSupportedIntegrations(nebConfig);
|
||||
const notSupported: SupportedIntegration[] = [];
|
||||
for (const supportedIntegration of supported) {
|
||||
let isSupported = false;
|
||||
for (const integration of knownIntegrations) {
|
||||
if (integration.type === supportedIntegration.type) {
|
||||
isSupported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSupported) notSupported.push(supportedIntegration);
|
||||
}
|
||||
|
||||
const promises = [];
|
||||
for (const missingIntegration of notSupported) {
|
||||
promises.push(NebStore.getOrCreateIntegration(nebConfig.id, missingIntegration.type));
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(addedIntegrations => (addedIntegrations || []).concat(knownIntegrations));
|
||||
}
|
||||
|
||||
public static getSupportedIntegrations(nebConfig: NebConfiguration): SupportedIntegration[] {
|
||||
const result = [];
|
||||
|
||||
for (const type of Object.keys(NebStore.INTEGRATIONS)) {
|
||||
if (nebConfig.upstreamId && NebStore.INTEGRATIONS_MODULAR_SUPPORTED.indexOf(type) === -1) continue;
|
||||
|
||||
const config = JSON.parse(JSON.stringify(NebStore.INTEGRATIONS[type]));
|
||||
config["type"] = type;
|
||||
result.push(config);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private constructor() {
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ export class ScalarStore {
|
||||
});
|
||||
}
|
||||
|
||||
public static getTokenOwner(scalarToken: string): Promise<User> {
|
||||
public static getTokenOwner(scalarToken: string, ignoreUpstreams?: boolean): Promise<User> {
|
||||
let user: User = null;
|
||||
return UserScalarToken.findAll({
|
||||
where: {isDimensionToken: true, scalarToken: scalarToken},
|
||||
@ -41,6 +41,7 @@ export class ScalarStore {
|
||||
}
|
||||
|
||||
user = tokens[0].user;
|
||||
if (ignoreUpstreams) return true; // they have all the upstreams as far as we're concerned
|
||||
return ScalarStore.doesUserHaveTokensForAllUpstreams(user.userId);
|
||||
}).then(hasUpstreams => {
|
||||
if (!hasUpstreams) {
|
||||
|
@ -1,13 +1,11 @@
|
||||
import * as dns from "dns-then";
|
||||
import * as Promise from "bluebird";
|
||||
import { LogService } from "matrix-js-snippets";
|
||||
import { MemoryCache } from "../MemoryCache";
|
||||
import { Cache, CACHE_FEDERATION } from "../MemoryCache";
|
||||
import * as request from "request";
|
||||
|
||||
const federationUrlCache = new MemoryCache();
|
||||
|
||||
export function getFederationUrl(serverName: string): Promise<string> {
|
||||
const cachedUrl = federationUrlCache.get(serverName);
|
||||
const cachedUrl = Cache.for(CACHE_FEDERATION).get(serverName);
|
||||
if (cachedUrl) {
|
||||
LogService.verbose("matrix", "Cached federation URL for " + serverName + " is " + cachedUrl);
|
||||
return Promise.resolve(cachedUrl);
|
||||
@ -30,7 +28,7 @@ export function getFederationUrl(serverName: string): Promise<string> {
|
||||
}).then(() => {
|
||||
if (!serverUrl) serverUrl = "https://" + serverName + ":8448";
|
||||
LogService.verbose("matrix", "Federation URL for " + serverName + " is " + serverUrl + " - caching for " + expirationMs + " ms");
|
||||
federationUrlCache.put(serverName, serverUrl, expirationMs);
|
||||
Cache.for(CACHE_FEDERATION).put(serverName, serverUrl, expirationMs);
|
||||
return serverUrl;
|
||||
});
|
||||
}
|
||||
|
19
src/models/neb.ts
Normal file
19
src/models/neb.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import NebConfiguration from "../db/models/NebConfiguration";
|
||||
import { Integration } from "../integrations/Integration";
|
||||
import NebIntegration from "../db/models/NebIntegration";
|
||||
|
||||
export class NebConfig {
|
||||
public id: number;
|
||||
public adminUrl?: string;
|
||||
public appserviceId?: string;
|
||||
public upstreamId?: number;
|
||||
public integrations: Integration[];
|
||||
|
||||
public constructor(config: NebConfiguration, integrations: NebIntegration[]) {
|
||||
this.id = config.id;
|
||||
this.adminUrl = config.adminUrl;
|
||||
this.appserviceId = config.appserviceId;
|
||||
this.upstreamId = config.upstreamId;
|
||||
this.integrations = integrations.map(i => new Integration(i));
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<ul class="adminNav">
|
||||
<li (click)="goto('')" [ngClass]="[isActive('', true) ? 'active' : '']">Dashboard</li>
|
||||
<li (click)="goto('widgets')" [ngClass]="[isActive('widgets') ? 'active' : '']">Widgets</li>
|
||||
<li (click)="goto('neb')" [ngClass]="[isActive('neb') ? 'active' : '']">go-neb</li>
|
||||
</ul>
|
||||
<span class="version">{{ version }}</span>
|
||||
|
||||
|
37
web/app/admin/neb/edit/edit.component.html
Normal file
37
web/app/admin/neb/edit/edit.component.html
Normal file
@ -0,0 +1,37 @@
|
||||
<div *ngIf="isLoading">
|
||||
<my-spinner></my-spinner>
|
||||
</div>
|
||||
<div *ngIf="!isLoading">
|
||||
<my-ibox title="go-neb configuration">
|
||||
<div class="my-ibox-content">
|
||||
<p>go-neb supports many different types of bots, each of which is listed below. Here you can configure which
|
||||
bots this go-neb instance should use.</p>
|
||||
|
||||
<table class="table table-striped table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th class="text-center">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let bot of nebConfig.integrations trackById">
|
||||
<td>{{ bot.displayName }}</td>
|
||||
<td>{{ bot.description }}</td>
|
||||
<td class="text-right">
|
||||
<span class="editButton" (click)="editBot(widget)"
|
||||
*ngIf="bot.isEnabled && hasConfig(bot) && !isUpstream">
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</span>
|
||||
<ui-switch [checked]="bot.isEnabled" size="small" [disabled]="isUpdating"
|
||||
(change)="toggleBot(bot)" *ngIf="!isOverlapping(bot)"></ui-switch>
|
||||
<ui-switch [checked]="false" size="small" [disabled]="true" *ngIf="isOverlapping(bot)"
|
||||
ngbTooltip="This bot is handled by another go-neb instance"></ui-switch>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</my-ibox>
|
||||
</div>
|
0
web/app/admin/neb/edit/edit.component.scss
Normal file
0
web/app/admin/neb/edit/edit.component.scss
Normal file
87
web/app/admin/neb/edit/edit.component.ts
Normal file
87
web/app/admin/neb/edit/edit.component.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FE_NebConfiguration } from "../../../shared/models/admin_responses";
|
||||
import { AdminNebApiService } from "../../../shared/services/admin/admin-neb-api.service";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { FE_Integration } from "../../../shared/models/integration";
|
||||
import { NEB_HAS_CONFIG } from "../../../shared/models/neb";
|
||||
|
||||
|
||||
@Component({
|
||||
templateUrl: "./edit.component.html",
|
||||
styleUrls: ["./edit.component.scss"],
|
||||
})
|
||||
export class AdminEditNebComponent implements OnInit, OnDestroy {
|
||||
|
||||
public isLoading = true;
|
||||
public isUpdating = false;
|
||||
public isUpstream = false;
|
||||
public nebConfig: FE_NebConfiguration;
|
||||
|
||||
private subscription: any;
|
||||
private overlappingTypes: string[];
|
||||
private botTypes: string[];
|
||||
|
||||
constructor(private nebApi: AdminNebApiService, private route: ActivatedRoute, private toaster: ToasterService) {
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
this.subscription = this.route.params.subscribe(params => {
|
||||
this.loadNeb(params["nebId"]);
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.subscription.unsubscribe();
|
||||
}
|
||||
|
||||
public isOverlapping(bot: FE_Integration) {
|
||||
return this.overlappingTypes.indexOf(bot.type) !== -1;
|
||||
}
|
||||
|
||||
public hasConfig(bot: FE_Integration): boolean {
|
||||
return NEB_HAS_CONFIG.indexOf(bot.type) !== -1;
|
||||
}
|
||||
|
||||
public toggleBot(bot: FE_Integration) {
|
||||
bot.isEnabled = !bot.isEnabled;
|
||||
this.isUpdating = true;
|
||||
this.nebApi.toggleIntegration(this.nebConfig.id, bot.type, bot.isEnabled).then(() => {
|
||||
this.isUpdating = false;
|
||||
this.toaster.pop("success", "Integration updated");
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
bot.isEnabled = !bot.isEnabled; // revert change
|
||||
this.isUpdating = false;
|
||||
this.toaster.pop("error", "Error updating integration");
|
||||
});
|
||||
}
|
||||
|
||||
public editBot(bot: FE_Integration) {
|
||||
console.log(bot);
|
||||
}
|
||||
|
||||
private loadNeb(nebId: number) {
|
||||
this.isLoading = true;
|
||||
this.nebApi.getConfigurations().then(configs => {
|
||||
const handledTypes: string[] = [];
|
||||
for (const config of configs) {
|
||||
if (config.id == nebId) {
|
||||
this.nebConfig = config;
|
||||
} else {
|
||||
for (const type of config.integrations) {
|
||||
this.botTypes.push(type.type);
|
||||
handledTypes.push(type.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.overlappingTypes = handledTypes;
|
||||
this.isUpstream = !!this.nebConfig.upstreamId;
|
||||
this.isLoading = false;
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
this.toaster.pop('error', "Could not get go-neb configuration");
|
||||
});
|
||||
}
|
||||
}
|
45
web/app/admin/neb/neb.component.html
Normal file
45
web/app/admin/neb/neb.component.html
Normal file
@ -0,0 +1,45 @@
|
||||
<div *ngIf="isLoading">
|
||||
<my-spinner></my-spinner>
|
||||
</div>
|
||||
<div *ngIf="!isLoading">
|
||||
<my-ibox title="go-neb configurations">
|
||||
<div class="my-ibox-content">
|
||||
<p><a href="https://github.com/matrix-org/go-neb" target="_blank">go-neb</a> is a multi-purpose bot that can
|
||||
provide various services, such as reaction GIFs and Github notifications. There are two options for
|
||||
go-neb support in Dimension: using matrix.org's or self-hosting it. Each go-neb instance can have
|
||||
multiple services associated with it (ie: one go-neb here can do everything).</p>
|
||||
|
||||
<table class="table table-striped table-condensed table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th class="text-center" style="width: 120px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngIf="!configurations || configurations.length === 0">
|
||||
<td colspan="2"><i>No go-neb configurations.</i></td>
|
||||
</tr>
|
||||
<tr *ngFor="let neb of configurations trackById">
|
||||
<td>{{ neb.upstreamId ? "matrix.org's go-neb" : "Self-hosted go-neb" }}</td>
|
||||
<td class="text-center">
|
||||
<span class="appsvcConfigButton" (click)="showAppserviceConfig(neb)"
|
||||
*ngIf="!neb.upstreamId">
|
||||
<i class="far fa-file"></i>
|
||||
</span>
|
||||
<span class="editButton" [routerLink]="[neb.id, 'edit']" title="edit">
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" class="btn btn-success btn-sm" (click)="addModularHostedNeb()" *ngIf="!hasModularNeb">
|
||||
<i class="fa fa-plus"></i> Add matrix.org's go-neb
|
||||
</button>
|
||||
<button type="button" class="btn btn-success btn-sm" (click)="addSelfHostedNeb()">
|
||||
<i class="fa fa-plus"></i> Add self-hosted go-neb
|
||||
</button>
|
||||
</div>
|
||||
</my-ibox>
|
||||
</div>
|
8
web/app/admin/neb/neb.component.scss
Normal file
8
web/app/admin/neb/neb.component.scss
Normal file
@ -0,0 +1,8 @@
|
||||
tr td:last-child {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.appsvcConfigButton,
|
||||
.editButton {
|
||||
cursor: pointer;
|
||||
}
|
103
web/app/admin/neb/neb.component.ts
Normal file
103
web/app/admin/neb/neb.component.ts
Normal file
@ -0,0 +1,103 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ToasterService } from "angular2-toaster";
|
||||
import { AdminNebApiService } from "../../shared/services/admin/admin-neb-api.service";
|
||||
import { AdminUpstreamApiService } from "../../shared/services/admin/admin-upstream-api.service";
|
||||
import { AdminAppserviceApiService } from "../../shared/services/admin/admin-appservice-api.service";
|
||||
import { FE_Appservice, FE_NebConfiguration, FE_Upstream } from "../../shared/models/admin_responses";
|
||||
|
||||
@Component({
|
||||
templateUrl: "./neb.component.html",
|
||||
styleUrls: ["./neb.component.scss"],
|
||||
})
|
||||
export class AdminNebComponent {
|
||||
|
||||
public isLoading = true;
|
||||
public isAddingModularNeb = false;
|
||||
public hasModularNeb = false;
|
||||
public upstreams: FE_Upstream[];
|
||||
public appservices: FE_Appservice[];
|
||||
public configurations: FE_NebConfiguration[];
|
||||
|
||||
constructor(private nebApi: AdminNebApiService,
|
||||
private upstreamApi: AdminUpstreamApiService,
|
||||
private appserviceApi: AdminAppserviceApiService,
|
||||
private toaster: ToasterService) {
|
||||
|
||||
this.reload().then(() => this.isLoading = false).catch(error => {
|
||||
console.error(error);
|
||||
this.toaster.pop("error", "Error loading go-neb configuration");
|
||||
});
|
||||
}
|
||||
|
||||
private reload(): Promise<any> {
|
||||
return Promise.all([
|
||||
this.loadAppservices(),
|
||||
this.loadConfigurations(),
|
||||
this.loadUpstreams(),
|
||||
]);
|
||||
}
|
||||
|
||||
private loadUpstreams(): Promise<any> {
|
||||
return this.upstreamApi.getUpstreams().then(upstreams => {
|
||||
this.upstreams = upstreams;
|
||||
});
|
||||
}
|
||||
|
||||
private loadAppservices(): Promise<any> {
|
||||
return this.appserviceApi.getAppservices().then(appservices => {
|
||||
this.appservices = appservices;
|
||||
});
|
||||
}
|
||||
|
||||
private loadConfigurations(): Promise<any> {
|
||||
return this.nebApi.getConfigurations().then(nebConfigs => {
|
||||
this.configurations = nebConfigs;
|
||||
this.isLoading = false;
|
||||
|
||||
this.hasModularNeb = false;
|
||||
for (const neb of this.configurations) {
|
||||
if (neb.upstreamId) {
|
||||
this.hasModularNeb = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public showAppserviceConfig(neb: FE_NebConfiguration) {
|
||||
console.log(neb);
|
||||
}
|
||||
|
||||
public addSelfHostedNeb() {
|
||||
console.log("ADD Hosted");
|
||||
}
|
||||
|
||||
public addModularHostedNeb() {
|
||||
this.isAddingModularNeb = true;
|
||||
const createNeb = (upstream: FE_Upstream) => {
|
||||
this.nebApi.newUpstreamConfiguration(upstream).then(neb => {
|
||||
this.configurations.push(neb);
|
||||
this.toaster.pop("success", "matrix.org's go-neb added", "Click the pencil icon to enable the bots.");
|
||||
this.isAddingModularNeb = false;
|
||||
this.hasModularNeb = true;
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
this.isAddingModularNeb = false;
|
||||
this.toaster.pop("error", "Error adding matrix.org's go-neb");
|
||||
});
|
||||
};
|
||||
|
||||
const vectorUpstreams = this.upstreams.filter(u => u.type === "vector");
|
||||
if (vectorUpstreams.length === 0) {
|
||||
console.log("Creating default scalar upstream");
|
||||
const scalarUrl = "https://scalar.vector.im/api";
|
||||
this.upstreamApi.newUpstream("modular", "vector", scalarUrl, scalarUrl).then(upstream => {
|
||||
this.upstreams.push(upstream);
|
||||
createNeb(upstream);
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
this.toaster.pop("error", "Error creating matrix.org go-neb");
|
||||
});
|
||||
} else createNeb(vectorUpstreams[0]);
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@
|
||||
<i class="fa fa-pencil-alt"></i>
|
||||
</span>
|
||||
<ui-switch [checked]="widget.isEnabled" size="small" [disabled]="isUpdating"
|
||||
(change)="disableWidget(widget)"></ui-switch>
|
||||
(change)="toggleWidget(widget)"></ui-switch>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -1,7 +1,3 @@
|
||||
ul {
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.editButton {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
@ -28,7 +28,7 @@ export class AdminWidgetsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
public disableWidget(widget: FE_Widget) {
|
||||
public toggleWidget(widget: FE_Widget) {
|
||||
widget.isEnabled = !widget.isEnabled;
|
||||
this.isUpdating = true;
|
||||
this.adminIntegrationsApi.toggleIntegration(widget.category, widget.type, widget.isEnabled).then(() => {
|
||||
@ -39,7 +39,7 @@ export class AdminWidgetsComponent {
|
||||
widget.isEnabled = !widget.isEnabled; // revert change
|
||||
this.isUpdating = false;
|
||||
this.toaster.pop("error", "Error updating widget");
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
public editWidget(widget: FE_Widget) {
|
||||
|
@ -47,6 +47,11 @@ import { AdminWidgetJitsiConfigComponent } from "./admin/widgets/jitsi/jitsi.com
|
||||
import { AdminIntegrationsApiService } from "./shared/services/admin/admin-integrations-api.service";
|
||||
import { IntegrationsApiService } from "./shared/services/integrations/integrations-api.service";
|
||||
import { WidgetApiService } from "./shared/services/integrations/widget-api.service";
|
||||
import { AdminAppserviceApiService } from "./shared/services/admin/admin-appservice-api.service";
|
||||
import { AdminNebApiService } from "./shared/services/admin/admin-neb-api.service";
|
||||
import { AdminUpstreamApiService } from "./shared/services/admin/admin-upstream-api.service";
|
||||
import { AdminNebComponent } from "./admin/neb/neb.component";
|
||||
import { AdminEditNebComponent } from "./admin/neb/edit/edit.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -91,6 +96,8 @@ import { WidgetApiService } from "./shared/services/integrations/widget-api.serv
|
||||
AdminWidgetsComponent,
|
||||
AdminWidgetEtherpadConfigComponent,
|
||||
AdminWidgetJitsiConfigComponent,
|
||||
AdminNebComponent,
|
||||
AdminEditNebComponent,
|
||||
|
||||
// Vendor
|
||||
],
|
||||
@ -102,6 +109,9 @@ import { WidgetApiService } from "./shared/services/integrations/widget-api.serv
|
||||
ScalarClientApiService,
|
||||
ScalarServerApiService,
|
||||
NameService,
|
||||
AdminAppserviceApiService,
|
||||
AdminNebApiService,
|
||||
AdminUpstreamApiService,
|
||||
{provide: Window, useValue: window},
|
||||
|
||||
// Vendor
|
||||
|
@ -16,6 +16,8 @@ import { YoutubeWidgetConfigComponent } from "./configs/widget/youtube/youtube.w
|
||||
import { AdminComponent } from "./admin/admin.component";
|
||||
import { AdminHomeComponent } from "./admin/home/home.component";
|
||||
import { AdminWidgetsComponent } from "./admin/widgets/widgets.component";
|
||||
import { AdminNebComponent } from "./admin/neb/neb.component";
|
||||
import { AdminEditNebComponent } from "./admin/neb/edit/edit.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: "", component: HomeComponent},
|
||||
@ -43,6 +45,21 @@ const routes: Routes = [
|
||||
component: AdminWidgetsComponent,
|
||||
data: {breadcrumb: "Widgets", name: "Widgets"},
|
||||
},
|
||||
{
|
||||
path: "neb",
|
||||
data: {breadcrumb: "go-neb", name: "go-neb configuration"},
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
component: AdminNebComponent,
|
||||
},
|
||||
{
|
||||
path: ":nebId/edit",
|
||||
component: AdminEditNebComponent,
|
||||
data: {breadcrumb: "Edit go-neb", name: "Edit go-neb"},
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { FE_Integration } from "./integration";
|
||||
|
||||
export interface FE_DimensionConfig {
|
||||
admins: string[];
|
||||
widgetBlacklist: string[];
|
||||
@ -10,4 +12,27 @@ export interface FE_DimensionConfig {
|
||||
|
||||
export interface FE_DimensionVersion {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface FE_Upstream {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
scalarUrl: string;
|
||||
apiUrl: string;
|
||||
}
|
||||
|
||||
export interface FE_Appservice {
|
||||
id: number;
|
||||
hsToken: string;
|
||||
asToken: string;
|
||||
userPrefix: string;
|
||||
}
|
||||
|
||||
export interface FE_NebConfiguration {
|
||||
id: number;
|
||||
adminUrl?: string;
|
||||
appserviceId?: string;
|
||||
upstreamId?: string;
|
||||
integrations: FE_Integration[];
|
||||
}
|
8
web/app/shared/models/neb.ts
Normal file
8
web/app/shared/models/neb.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const NEB_HAS_CONFIG = [
|
||||
"giphy",
|
||||
"guggy",
|
||||
"github",
|
||||
"google",
|
||||
"imgur",
|
||||
"wikipedia",
|
||||
];
|
@ -0,0 +1,15 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { AuthedApi } from "../AuthedApi";
|
||||
import { FE_Appservice } from "../../models/admin_responses";
|
||||
|
||||
@Injectable()
|
||||
export class AdminAppserviceApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http);
|
||||
}
|
||||
|
||||
public getAppservices(): Promise<FE_Appservice[]> {
|
||||
return this.authedGet("/api/v1/dimension/admin/appservices/all").map(r => r.json()).toPromise();
|
||||
}
|
||||
}
|
@ -10,14 +10,14 @@ export class AdminIntegrationsApiService extends AuthedApi {
|
||||
}
|
||||
|
||||
public getAllIntegrations(): Promise<FE_IntegrationsResponse> {
|
||||
return this.authedGet("/api/v1/dimension/integrations/all").map(r => r.json()).toPromise();
|
||||
return this.authedGet("/api/v1/dimension/admin/integrations/all").map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public toggleIntegration(category: string, type: string, enabled: boolean): Promise<any> {
|
||||
return this.authedPost("/api/v1/dimension/integrations/" + category + "/" + type + "/enabled", {enabled: enabled}).map(r => r.json()).toPromise();
|
||||
return this.authedPost("/api/v1/dimension/admin/integrations/" + category + "/" + type + "/enabled", {enabled: enabled}).map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public setIntegrationOptions(category: string, type: string, options: any): Promise<any> {
|
||||
return this.authedPost("/api/v1/dimension/integrations/" + category + "/" + type + "/options", {options: options}).map(r => r.json()).toPromise();
|
||||
return this.authedPost("/api/v1/dimension/admin/integrations/" + category + "/" + type + "/options", {options: options}).map(r => r.json()).toPromise();
|
||||
}
|
||||
}
|
||||
|
34
web/app/shared/services/admin/admin-neb-api.service.ts
Normal file
34
web/app/shared/services/admin/admin-neb-api.service.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { AuthedApi } from "../AuthedApi";
|
||||
import { FE_Appservice, FE_NebConfiguration, FE_Upstream } from "../../models/admin_responses";
|
||||
|
||||
@Injectable()
|
||||
export class AdminNebApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http);
|
||||
}
|
||||
|
||||
public getConfigurations(): Promise<FE_NebConfiguration[]> {
|
||||
return this.authedGet("/api/v1/dimension/admin/neb/all").map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public getConfiguration(nebId: number): Promise<FE_NebConfiguration> {
|
||||
return this.authedGet("/api/v1/dimension/admin/neb/" + nebId + "/config").map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public newUpstreamConfiguration(upstream: FE_Upstream): Promise<FE_NebConfiguration> {
|
||||
return this.authedPost("/api/v1/dimension/admin/neb/new/upstream", {upstreamId: upstream.id}).map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public newAppserviceConfiguration(adminUrl: string, appservice: FE_Appservice): Promise<FE_NebConfiguration> {
|
||||
return this.authedPost("/api/v1/dimension/admin/neb/new/appservice", {
|
||||
adminUrl: adminUrl,
|
||||
appserviceId: appservice.id
|
||||
}).map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public toggleIntegration(nebId: number, integrationType: string, setEnabled: boolean): Promise<any> {
|
||||
return this.authedPost("/api/v1/dimension/admin/neb/" + nebId + "/integration/" + integrationType + "/enabled", {enabled: setEnabled}).map(r => r.json()).toPromise();
|
||||
}
|
||||
}
|
24
web/app/shared/services/admin/admin-upstream-api.service.ts
Normal file
24
web/app/shared/services/admin/admin-upstream-api.service.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { Http } from "@angular/http";
|
||||
import { AuthedApi } from "../AuthedApi";
|
||||
import { FE_Upstream } from "../../models/admin_responses";
|
||||
|
||||
@Injectable()
|
||||
export class AdminUpstreamApiService extends AuthedApi {
|
||||
constructor(http: Http) {
|
||||
super(http);
|
||||
}
|
||||
|
||||
public getUpstreams(): Promise<FE_Upstream[]> {
|
||||
return this.authedGet("/api/v1/dimension/admin/upstreams/all").map(r => r.json()).toPromise();
|
||||
}
|
||||
|
||||
public newUpstream(name: string, type: string, scalarUrl: string, apiUrl: string): Promise<FE_Upstream> {
|
||||
return this.authedPost("/api/v1/dimension/admin/upstreams/new", {
|
||||
name: name,
|
||||
type: type,
|
||||
scalarUrl: scalarUrl,
|
||||
apiUrl: apiUrl,
|
||||
}).map(r => r.json()).toPromise();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user