Upgrade everything to Angular 12 and more + build changes
This is a very big commit that does an initial job of upgrading everything to the latest version. TSLint gets replaced by ESLint. Instead of plain node, now ts-node is being used. Old modules also get replaced with new ones (mostly ng2 to ngx). Also obsolete configs have been replaced with how it's used today with Angular. This includes: * Upgrade to: ** Angular 12 ** Typescript 4 ** ESLint 7 and replace TSLint ** Bootstrap 5 ** Eerything connected to these * Run with ts-node * Convert wepack config to angular config * Remove typescript-ioc * Update tsconfigs * Run a git command instead of using a library for sshort hash * Move assets to a new location align with default Angular settings * Database migration for new avatarUrl locations * Simplify Model extension align with newest sequelize version * Remove breadcrumb hack * Fix homeserver typo * A few general fixes that are necessary with newest Typescript rules * Define Express.User interface
6
.eslintignore
Normal file
@ -0,0 +1,6 @@
|
||||
# don't ever lint node_modules
|
||||
node_modules
|
||||
# don't lint build output (make sure it's set to your correct build folder name)
|
||||
build
|
||||
# don't lint nyc coverage output
|
||||
coverage
|
50
.eslintrc.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"root": true,
|
||||
"ignorePatterns": [
|
||||
"projects/**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts"
|
||||
],
|
||||
"parserOptions": {
|
||||
"project": [
|
||||
"tsconfig.json"
|
||||
],
|
||||
"createDefaultProgram": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/recommended",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.html"
|
||||
],
|
||||
"extends": [
|
||||
"plugin:@angular-eslint/template/recommended"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
119
angular.json
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"dimension": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:application": {
|
||||
"strict": true
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "web",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "build/web",
|
||||
"index": "web/index.html",
|
||||
"main": "web/main.ts",
|
||||
"polyfills": "web/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"web/assets"
|
||||
],
|
||||
"styles": [
|
||||
"web/style/app.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"progress": true
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "4mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "32kb"
|
||||
}
|
||||
],
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "web/environments/environment.ts",
|
||||
"with": "web/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"buildOptimizer": false,
|
||||
"optimization": false,
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true,
|
||||
"namedChunks": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "dimension:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "dimension:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"proxyConfig": "proxy.conf.json"
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "dimension:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "web/test.ts",
|
||||
"polyfills": "web/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": [
|
||||
"web/favicon.ico",
|
||||
"web/assets"
|
||||
],
|
||||
"styles": [],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-eslint/builder:lint",
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "dimension",
|
||||
"cli": {
|
||||
"defaultCollection": "@angular-eslint/schematics"
|
||||
}
|
||||
}
|
45
karma.conf.js
Normal file
@ -0,0 +1,45 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {
|
||||
// you can add configuration options for Jasmine here
|
||||
// the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
|
||||
// for example, you can disable the random execution with `random: false`
|
||||
// or set a specific seed with `seed: 4321`
|
||||
},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/angular-starter'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
||||
|
16428
package-lock.json
generated
183
package.json
@ -5,18 +5,17 @@
|
||||
"main": "build/app/index.js",
|
||||
"license": "GPL-3.0",
|
||||
"scripts": {
|
||||
"start:web": "webpack-dev-server --inline --mode=development --progress --port 8082 --host 0.0.0.0",
|
||||
"ng": "ng",
|
||||
"start:web": "ng serve --configuration development --port 8082",
|
||||
"start:app": "npm run-script build && node build/app/index.js",
|
||||
"start:apponly": "npm run-script build:app && node build/app/index.js",
|
||||
"start:apponly": "ts-node-dev --respawn --transpile-only --project tsconfig.backend.json ./src/index.ts",
|
||||
"node:start:apponly": "npm run-script build:app && node build/app/index.js",
|
||||
"build": "npm run-script build:web && npm run-script build:app",
|
||||
"build:web": "rimraf build/web && webpack --mode production --progress --profile --bail",
|
||||
"build:app": "rimraf build/app && tsc -p tsconfig-app.json",
|
||||
"build:web": "rimraf build/web && ng build --configuration production",
|
||||
"build:app": "rimraf build/app && tsc -p tsconfig.backend.json",
|
||||
"lint": "npm run-script lint:app && npm run-script lint:web",
|
||||
"lint:app": "tslint --project ./tsconfig-app.json -t stylish",
|
||||
"lint:web": "tslint --project ./tsconfig.json -t stylish",
|
||||
"i18n": "npm run-script i18n:init && npm run-script i18n:extract",
|
||||
"i18n:init": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/template.json --key-as-default-value --replace --format json",
|
||||
"i18n:extract": "ngx-translate-extract --input ./web --output ./web/public/assets/i18n/en.json --clean --format json"
|
||||
"lint:app": "tslint --project ./tsconfig.app.json",
|
||||
"lint:web": "tslint --project ./tsconfig.json"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -24,113 +23,121 @@
|
||||
},
|
||||
"author": "Travis Ralston",
|
||||
"dependencies": {
|
||||
"@ngx-translate/core": "^12.1.2",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@types/bluebird": "^3.5.27",
|
||||
"@types/body-parser": "^1.17.0",
|
||||
"@types/node": "^12.0.10",
|
||||
"@types/validator": "^10.11.1",
|
||||
"@angular/localize": "^12.1.1",
|
||||
"@fortawesome/angular-fontawesome": "^0.9.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@popperjs/core": "^2.9.2",
|
||||
"body-parser": "^1.19.0",
|
||||
"config": "^3.1.0",
|
||||
"config": "^3.3.6",
|
||||
"dns-then": "^0.1.0",
|
||||
"express": "^4.17.1",
|
||||
"git-rev-sync": "^1.12.0",
|
||||
"isipaddress": "0.0.2",
|
||||
"js-yaml": "^3.13.1",
|
||||
"lodash": "^4.17.19",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"matrix-bot-sdk": "^0.3.8",
|
||||
"matrix-js-snippets": "^0.2.8",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mime": "^2.4.2",
|
||||
"moment": "^2.24.0",
|
||||
"netmask": "^1.0.6",
|
||||
"pg": "^8.5.1",
|
||||
"mime": "^2.5.2",
|
||||
"moment": "^2.29.1",
|
||||
"netmask": "^2.0.2",
|
||||
"ngx-ui-switch": "^12.0.1",
|
||||
"postcss": "^8.3.5",
|
||||
"random-string": "^0.2.0",
|
||||
"request": "^2.88.0",
|
||||
"request-promise": "^4.2.4",
|
||||
"request": "^2.88.2",
|
||||
"request-promise": "^4.2.6",
|
||||
"require-dir-all": "^0.4.15",
|
||||
"semver": "^6.0.0",
|
||||
"sequelize": "^5.18.4",
|
||||
"sequelize-typescript": "^1.0.0",
|
||||
"sharp": "^0.27.2",
|
||||
"semver": "^7.3.5",
|
||||
"sequelize": "6.6.2",
|
||||
"sequelize-typescript": "^2.1.0",
|
||||
"sharp": "^0.28.3",
|
||||
"split-host": "^0.1.1",
|
||||
"spotify-uri": "^1.0.0",
|
||||
"sqlite3": "^4.2.0",
|
||||
"spotify-uri": "^2.2.0",
|
||||
"sqlite3": "^5.0.2",
|
||||
"telegraf": "^3.30.1",
|
||||
"typescript": "^3.5.2",
|
||||
"typescript-ioc": "^1.2.5",
|
||||
"typescript-rest": "^2.2.0",
|
||||
"umzug": "^2.2.0",
|
||||
"typescript": "^4.3.5",
|
||||
"typescript-rest": "^3.0.4",
|
||||
"umzug": "^3.0.0-beta.16",
|
||||
"url": "^0.11.0",
|
||||
"xml2js": "^0.4.23"
|
||||
"xng-breadcrumb": "^6.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/core": "^11.2.4",
|
||||
"@angular/animations": "^11.2.5",
|
||||
"@angular/common": "^11.2.5",
|
||||
"@angular/compiler": "^11.2.5",
|
||||
"@angular/core": "^11.2.5",
|
||||
"@angular/forms": "^11.2.5",
|
||||
"@angular/platform-browser": "^11.2.5",
|
||||
"@angular/platform-browser-dynamic": "^11.2.5",
|
||||
"@angular/router": "^11.2.5",
|
||||
"@angularclass/hmr": "^2.1.3",
|
||||
"@angular-devkit/build-angular": "^12.1.1",
|
||||
"@angular-devkit/core": "^12.1.1",
|
||||
"@angular-eslint/builder": "12.3.0",
|
||||
"@angular-eslint/eslint-plugin": "12.3.0",
|
||||
"@angular-eslint/eslint-plugin-template": "12.3.0",
|
||||
"@angular-eslint/schematics": "12.3.0",
|
||||
"@angular-eslint/template-parser": "12.3.0",
|
||||
"@angular/animations": "^12.1.1",
|
||||
"@angular/cli": "^12.1.1",
|
||||
"@angular/common": "^12.1.1",
|
||||
"@angular/compiler": "^12.1.1",
|
||||
"@angular/compiler-cli": "^12.1.1",
|
||||
"@angular/core": "^12.1.1",
|
||||
"@angular/forms": "^12.1.1",
|
||||
"@angular/platform-browser": "^12.1.1",
|
||||
"@angular/platform-browser-dynamic": "^12.1.1",
|
||||
"@angular/router": "^12.1.1",
|
||||
"@angularclass/hmr": "^3.0.0",
|
||||
"@angularclass/hmr-loader": "^3.0.4",
|
||||
"@babel/core": "^7.4.5",
|
||||
"@babel/preset-env": "^7.4.5",
|
||||
"@biesbjerg/ngx-translate-extract": "^7.0.3",
|
||||
"@ckeditor/ckeditor5-angular": "^1.1.0",
|
||||
"@ckeditor/ckeditor5-build-classic": "^12.2.0",
|
||||
"@babel/core": "^7.14.6",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@ckeditor/ckeditor5-angular": "^2.0.2",
|
||||
"@ckeditor/ckeditor5-build-classic": "^29.0.0",
|
||||
"@fortawesome/fontawesome": "^1.1.8",
|
||||
"@fortawesome/fontawesome-free-brands": "^5.0.13",
|
||||
"@fortawesome/fontawesome-free-regular": "^5.0.13",
|
||||
"@fortawesome/fontawesome-free-solid": "^5.0.13",
|
||||
"@ng-bootstrap/ng-bootstrap": "^4.2.1",
|
||||
"@types/jquery": "^3.3.30",
|
||||
"@ng-bootstrap/ng-bootstrap": "^11.0.0-beta.2",
|
||||
"@types/bluebird": "^3.5.36",
|
||||
"@types/body-parser": "^1.19.1",
|
||||
"@types/jquery": "^3.5.6",
|
||||
"@types/node": "^14.17.4",
|
||||
"@types/validator": "^13.6.3",
|
||||
"@typescript-eslint/eslint-plugin": "4.28.2",
|
||||
"@typescript-eslint/parser": "4.28.2",
|
||||
"angular2-template-loader": "^0.6.2",
|
||||
"angular2-toaster": "^7.0.0",
|
||||
"angular2-ui-switch": "^1.2.0",
|
||||
"awesome-typescript-loader": "^5.2.1",
|
||||
"bootstrap": "^4.3.1",
|
||||
"codelyzer": "^5.1.0",
|
||||
"copy-webpack-plugin": "^5.1.2",
|
||||
"core-js": "^3.1.4",
|
||||
"css-loader": "^3.0.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"angular2-toaster": "^11.0.1",
|
||||
"bootstrap": "^5.0.2",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
"core-js": "^3.15.2",
|
||||
"css-loader": "^5.2.7",
|
||||
"cssnano": "^5.0.6",
|
||||
"dom-to-image": "^2.6.0",
|
||||
"embed-video": "^2.0.4",
|
||||
"file-loader": "^4.0.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-webpack-plugin": "^2.5.4",
|
||||
"goby": "^1.1.2",
|
||||
"html-loader": "^0.5.5",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"iso-639-1": "^2.0.5",
|
||||
"jquery": "^3.5.0",
|
||||
"html-loader": "^2.1.2",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"iso-639-1": "^2.1.9",
|
||||
"jquery": "^3.6.0",
|
||||
"json-loader": "^0.5.7",
|
||||
"mini-css-extract-plugin": "^0.7.0",
|
||||
"ng2-breadcrumbs": "^0.1.281",
|
||||
"mini-css-extract-plugin": "^2.1.0",
|
||||
"ngx-modialog": "^5.0.1",
|
||||
"node-sass": "^4.14.1",
|
||||
"postcss-cssnext": "^3.1.0",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-scss": "^2.0.0",
|
||||
"raw-loader": "1.0.0",
|
||||
"postcss-import": "^14.0.2",
|
||||
"postcss-loader": "^6.1.1",
|
||||
"postcss-scss": "^4.0.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^2.6.3",
|
||||
"rxjs": "^6.6.6",
|
||||
"rxjs-compat": "^6.5.2",
|
||||
"sass-loader": "^7.1.0",
|
||||
"screenfull": "^4.2.0",
|
||||
"shelljs": "^0.8.3",
|
||||
"spinkit": "^1.2.5",
|
||||
"style-loader": "^0.23.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^6.6.7",
|
||||
"rxjs-compat": "^6.6.7",
|
||||
"sass-loader": "^12.1.0",
|
||||
"screenfull": "^5.1.0",
|
||||
"shelljs": "^0.8.4",
|
||||
"spinkit": "^2.0.1",
|
||||
"style-loader": "^3.1.0",
|
||||
"ts-helpers": "^1.1.2",
|
||||
"tslint": "^5.18.0",
|
||||
"tslint-loader": "^3.5.4",
|
||||
"url-loader": "^2.0.1",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "^3.3.5",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
"ts-loader": "^9.2.3",
|
||||
"ts-node": "^10.1.0",
|
||||
"ts-node-dev": "^1.1.8",
|
||||
"webpack": "^5.44.0",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"zone.js": "^0.11.4"
|
||||
}
|
||||
}
|
14
proxy.conf.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"/api": {
|
||||
"target": "http://localhost:8184",
|
||||
"secure": false
|
||||
},
|
||||
"/_matrix": {
|
||||
"target": "http://localhost:8184",
|
||||
"secure": false
|
||||
},
|
||||
"/.well-known": {
|
||||
"target": "http://localhost:8184",
|
||||
"secure": false
|
||||
}
|
||||
}
|
@ -26,9 +26,8 @@ export default class Webserver {
|
||||
private loadRoutes() {
|
||||
// TODO: Rename services to controllers, and controllers to services. They're backwards.
|
||||
|
||||
const apis = ["scalar", "dimension", "admin", "matrix"].map(a => path.join(__dirname, a, "*.js"));
|
||||
const apis = ["scalar", "dimension", "admin", "matrix"].map(a => path.join(__dirname, a, "*"));
|
||||
const router = express.Router();
|
||||
Server.useIoC();
|
||||
Server.registerAuthenticator(new MatrixSecurity());
|
||||
apis.forEach(a => Server.loadServices(router, [a]));
|
||||
const routes = _.uniq(router.stack.map(r => r.route.path));
|
||||
|
@ -89,7 +89,7 @@ export class AdminStickerService {
|
||||
authorName: "Telegram",
|
||||
authorReference: request.packUrl,
|
||||
license: "Telegram",
|
||||
licensePath: "/licenses/telegram-imported.txt",
|
||||
licensePath: "/assets/licenses/telegram-imported.txt",
|
||||
});
|
||||
|
||||
const stickers = [];
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { GET, Path, PathParam, POST, PUT, Security } from "typescript-rest";
|
||||
import TermsController, { ITerms } from "../controllers/TermsController";
|
||||
import { AutoWired, Inject } from "typescript-ioc/es6";
|
||||
import { ROLE_ADMIN, ROLE_USER } from "../security/MatrixSecurity";
|
||||
|
||||
interface CreatePolicyObject {
|
||||
@ -13,44 +12,40 @@ interface CreatePolicyObject {
|
||||
* Administrative API for configuring terms of service.
|
||||
*/
|
||||
@Path("/api/v1/dimension/admin/terms")
|
||||
@AutoWired
|
||||
export class AdminTermsService {
|
||||
|
||||
@Inject
|
||||
private termsController: TermsController;
|
||||
|
||||
@GET
|
||||
@Path("all")
|
||||
@Security([ROLE_USER, ROLE_ADMIN])
|
||||
public async getPolicies(): Promise<ITerms[]> {
|
||||
return this.termsController.getPoliciesForAdmin();
|
||||
return new TermsController().getPoliciesForAdmin();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path(":shortcode/:version")
|
||||
@Security([ROLE_USER, ROLE_ADMIN])
|
||||
public async getPolicy(@PathParam("shortcode") shortcode: string, @PathParam("version") version: string): Promise<ITerms> {
|
||||
return this.termsController.getPolicyForAdmin(shortcode, version);
|
||||
return new TermsController().getPolicyForAdmin(shortcode, version);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path(":shortcode/draft")
|
||||
@Security([ROLE_USER, ROLE_ADMIN])
|
||||
public async createDraftPolicy(@PathParam("shortcode") shortcode: string, request: CreatePolicyObject): Promise<ITerms> {
|
||||
return this.termsController.createDraftPolicy(request.name, shortcode, request.text, request.url);
|
||||
return new TermsController().createDraftPolicy(request.name, shortcode, request.text, request.url);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path(":shortcode/publish/:version")
|
||||
@Security([ROLE_USER, ROLE_ADMIN])
|
||||
public async publishDraftPolicy(@PathParam("shortcode") shortcode: string, @PathParam("version") version: string): Promise<ITerms> {
|
||||
return this.termsController.publishPolicy(shortcode, version);
|
||||
return new TermsController().publishPolicy(shortcode, version);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path(":shortcode/:version")
|
||||
@Security([ROLE_USER, ROLE_ADMIN])
|
||||
public async updatePolicy(@PathParam("shortcode") shortcode: string, @PathParam("version") version: string, request: CreatePolicyObject): Promise<ITerms> {
|
||||
return this.termsController.updatePolicy(request.name, shortcode, version, request.text, request.url);
|
||||
return new TermsController().updatePolicy(request.name, shortcode, version, request.text, request.url);
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ import { ScalarStore } from "../../db/ScalarStore";
|
||||
import UserScalarToken from "../../db/models/UserScalarToken";
|
||||
import { ScalarClient } from "../../scalar/ScalarClient";
|
||||
import * as randomString from "random-string";
|
||||
import { AutoWired } from "typescript-ioc/es6";
|
||||
import { Cache, CACHE_SCALAR_ACCOUNTS } from "../../MemoryCache";
|
||||
import { ILoggedInUser } from "../security/MatrixSecurity";
|
||||
|
||||
@ -23,7 +22,6 @@ export interface IAccountInfoResponse {
|
||||
/**
|
||||
* API controller for account management
|
||||
*/
|
||||
@AutoWired
|
||||
export default class AccountController {
|
||||
constructor() {
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { AutoWired } from "typescript-ioc/es6";
|
||||
import { ILoggedInUser } from "../security/MatrixSecurity";
|
||||
import TermsRecord from "../../db/models/TermsRecord";
|
||||
import TermsTextRecord from "../../db/models/TermsTextRecord";
|
||||
@ -50,11 +49,7 @@ export const VERSION_DRAFT = "draft";
|
||||
/**
|
||||
* API controller for terms of service management
|
||||
*/
|
||||
@AutoWired
|
||||
export default class TermsController {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
private async getPublishedTerms(): Promise<ICachedTerms[]> {
|
||||
const cache = Cache.for(CACHE_TERMS);
|
||||
|
||||
|
@ -29,7 +29,7 @@ export class DimensionWebhooksService {
|
||||
|
||||
@POST
|
||||
@Path("/travisci/:webhookId")
|
||||
public async postTravisCiWebhook(@PathParam("webhookId") webhookId: string, @FormParam("payload") payload: string, @HeaderParam("Signature") signature: string): Promise<any> {
|
||||
public async postTravisCiWebhook(@PathParam("webhookId") webhookId: string, @FormParam("payload") payload: string, @HeaderParam("Signature") signature: string): Promise<void> {
|
||||
const webhook = await Webhook.findByPk(webhookId).catch(() => null);
|
||||
if (!webhook) throw new ApiError(404, "Webhook not found");
|
||||
if (!webhook.targetUrl) throw new ApiError(400, "Webhook not configured");
|
||||
|
@ -76,7 +76,7 @@ export class DimensionWidgetService {
|
||||
}
|
||||
|
||||
// Now we need to verify we can actually make the request
|
||||
await new Promise((resolve, reject) => {
|
||||
await new Promise<ApiError | void>((resolve, reject) => {
|
||||
request(checkUrl, (err, response) => {
|
||||
if (err) {
|
||||
LogService.error("DimensionWidgetService", err);
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Context, GET, Path, POST, Security, ServiceContext } from "typescript-rest";
|
||||
import { OpenId } from "../../models/OpenId";
|
||||
import AccountController, { IAccountInfoResponse, IAccountRegisteredResponse } from "../controllers/AccountController";
|
||||
import { AutoWired, Inject } from "typescript-ioc/es6";
|
||||
import { ILoggedInUser, ROLE_USER } from "../security/MatrixSecurity";
|
||||
import { ScalarClient } from "../../scalar/ScalarClient";
|
||||
|
||||
@ -9,19 +8,15 @@ import { ScalarClient } from "../../scalar/ScalarClient";
|
||||
* API for account management
|
||||
*/
|
||||
@Path("/_matrix/integrations/v1/account")
|
||||
@AutoWired
|
||||
export class MatrixAccountService {
|
||||
|
||||
@Inject
|
||||
private accountController: AccountController;
|
||||
|
||||
@Context
|
||||
private context: ServiceContext;
|
||||
|
||||
@POST
|
||||
@Path("register")
|
||||
public async register(request: OpenId): Promise<IAccountRegisteredResponse> {
|
||||
return this.accountController.registerAccount(request, ScalarClient.KIND_MATRIX_V1);
|
||||
return new AccountController().registerAccount(request, ScalarClient.KIND_MATRIX_V1);
|
||||
}
|
||||
|
||||
@GET
|
||||
@ -36,7 +31,7 @@ export class MatrixAccountService {
|
||||
@Path("logout")
|
||||
@Security(ROLE_USER)
|
||||
public async logout(): Promise<any> {
|
||||
await this.accountController.logout(this.context.request.user);
|
||||
await new AccountController().logout(this.context.request.user);
|
||||
return {};
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { Context, GET, Path, POST, Security, ServiceContext } from "typescript-rest";
|
||||
import { AutoWired, Inject } from "typescript-ioc/es6";
|
||||
import { ROLE_USER } from "../security/MatrixSecurity";
|
||||
import TermsController, { ITermsResponse } from "../controllers/TermsController";
|
||||
|
||||
@ -11,26 +10,22 @@ export interface SignTermsRequest {
|
||||
* API for account management
|
||||
*/
|
||||
@Path("/_matrix/integrations/v1/terms")
|
||||
@AutoWired
|
||||
export class MatrixTermsService {
|
||||
|
||||
@Inject
|
||||
private termsController: TermsController;
|
||||
|
||||
@Context
|
||||
private context: ServiceContext;
|
||||
|
||||
@GET
|
||||
@Path("")
|
||||
public async getAllTerms(): Promise<ITermsResponse> {
|
||||
return this.termsController.getAvailableTerms();
|
||||
return new TermsController().getAvailableTerms();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("")
|
||||
@Security(ROLE_USER)
|
||||
public async signTerms(request: SignTermsRequest): Promise<any> {
|
||||
await this.termsController.signTermsMatching(this.context.request.user, request.user_accepts);
|
||||
await new TermsController().signTermsMatching(this.context.request.user, request.user_accepts);
|
||||
return {};
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { GET, Path } from "typescript-rest";
|
||||
import { AutoWired } from "typescript-ioc/es6";
|
||||
import { URL } from "url";
|
||||
import config from "../../config";
|
||||
|
||||
@ -16,7 +15,6 @@ interface WellknownResponse {
|
||||
* Serving of the .well-known file
|
||||
*/
|
||||
@Path("/.well-known/matrix")
|
||||
@AutoWired
|
||||
export class MatrixWellknownService {
|
||||
|
||||
@GET
|
||||
|
@ -2,7 +2,6 @@ import { Context, GET, Path, POST, QueryParam, Security, ServiceContext } from "
|
||||
import { ApiError } from "../ApiError";
|
||||
import { OpenId } from "../../models/OpenId";
|
||||
import { ScalarAccountResponse, ScalarRegisterResponse } from "../../models/ScalarResponses";
|
||||
import { AutoWired, Inject } from "typescript-ioc/es6";
|
||||
import AccountController from "../controllers/AccountController";
|
||||
import { ROLE_USER } from "../security/MatrixSecurity";
|
||||
import TermsController, { ITermsResponse } from "../controllers/TermsController";
|
||||
@ -14,15 +13,8 @@ import { ScalarClient } from "../../scalar/ScalarClient";
|
||||
* and general account management.
|
||||
*/
|
||||
@Path("/api/v1/scalar")
|
||||
@AutoWired
|
||||
export class ScalarService {
|
||||
|
||||
@Inject
|
||||
private accountController: AccountController;
|
||||
|
||||
@Inject
|
||||
private termsController: TermsController;
|
||||
|
||||
@Context
|
||||
private context: ServiceContext;
|
||||
|
||||
@ -33,7 +25,7 @@ export class ScalarService {
|
||||
throw new ApiError(401, "Invalid API version.");
|
||||
}
|
||||
|
||||
const response = await this.accountController.registerAccount(request, ScalarClient.KIND_LEGACY);
|
||||
const response = await new AccountController().registerAccount(request, ScalarClient.KIND_LEGACY);
|
||||
return {scalar_token: response.token};
|
||||
}
|
||||
|
||||
@ -51,14 +43,14 @@ export class ScalarService {
|
||||
@GET
|
||||
@Path("terms")
|
||||
public async getTerms(): Promise<ITermsResponse> {
|
||||
return this.termsController.getAvailableTerms();
|
||||
return new TermsController().getAvailableTerms();
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("terms")
|
||||
@Security(ROLE_USER)
|
||||
public async signTerms(request: SignTermsRequest): Promise<any> {
|
||||
await this.termsController.signTermsMatching(this.context.request.user, request.user_accepts);
|
||||
await new TermsController().signTermsMatching(this.context.request.user, request.user_accepts);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Cache, CACHE_WIDGET_TITLES } from "../../MemoryCache";
|
||||
import { MatrixLiteClient } from "../../matrix/MatrixLiteClient";
|
||||
import config from "../../config";
|
||||
import { ROLE_USER } from "../security/MatrixSecurity";
|
||||
import moment = require("moment");
|
||||
import moment from 'moment';
|
||||
|
||||
interface UrlPreviewResponse {
|
||||
cached_response: boolean;
|
||||
|
@ -6,7 +6,7 @@ import UserScalarToken from "./models/UserScalarToken";
|
||||
import Upstream from "./models/Upstream";
|
||||
import WidgetRecord from "./models/WidgetRecord";
|
||||
import * as path from "path";
|
||||
import * as Umzug from "umzug";
|
||||
import { SequelizeStorage, Umzug } from "umzug";
|
||||
import AppService from "./models/AppService";
|
||||
import AppServiceUser from "./models/AppServiceUser";
|
||||
import NebConfiguration from "./models/NebConfiguration";
|
||||
@ -79,15 +79,20 @@ class _DimensionStore {
|
||||
}
|
||||
|
||||
public updateSchema(): Promise<any> {
|
||||
LogService.info("DimensionStore", "Updating schema...");
|
||||
LogService.info("DimensionStore", "Updating schema...",);
|
||||
|
||||
const migrator = new Umzug({
|
||||
storage: "sequelize",
|
||||
storageOptions: {sequelize: this.sequelize},
|
||||
migrations: {
|
||||
params: [this.sequelize.getQueryInterface()],
|
||||
path: path.join(__dirname, "migrations"),
|
||||
}
|
||||
glob: path.join(__dirname, "migrations/*"),
|
||||
resolve: ({name, path, context}) => {
|
||||
// Adjust the migration from the new signature to the v2 signature, making easier to upgrade to v3
|
||||
const migration = require(path)
|
||||
return { name, up: async () => migration.default.up(context), down: async () => migration.default.down(context) }
|
||||
}
|
||||
},
|
||||
context: this.sequelize.getQueryInterface(),
|
||||
storage: new SequelizeStorage({ sequelize: this.sequelize }),
|
||||
logger: console
|
||||
});
|
||||
|
||||
return migrator.up();
|
||||
|
@ -28,69 +28,69 @@ export class NebStore {
|
||||
// TODO: Support Circle CI
|
||||
// "circleci": {
|
||||
// name: "Circle CI",
|
||||
// avatarUrl: "/img/avatars/circleci.png",
|
||||
// avatarUrl: "/assets/img/avatars/circleci.png",
|
||||
// description: "Announces build results from Circle CI to the room.",
|
||||
// simple: false,
|
||||
// },
|
||||
"echo": {
|
||||
name: "Echo",
|
||||
avatarUrl: "/img/avatars/echo.png", // TODO: Make this image
|
||||
avatarUrl: "/assets/img/avatars/echo.png", // TODO: Make this image
|
||||
description: "Repeats text given to it from !echo",
|
||||
simple: true,
|
||||
},
|
||||
"giphy": {
|
||||
name: "Giphy",
|
||||
avatarUrl: "/img/avatars/giphy.png",
|
||||
avatarUrl: "/assets/img/avatars/giphy.png",
|
||||
description: "Posts a GIF from Giphy using !giphy <query>",
|
||||
simple: true,
|
||||
},
|
||||
"guggy": {
|
||||
name: "Guggy",
|
||||
avatarUrl: "/img/avatars/guggy.png",
|
||||
avatarUrl: "/assets/img/avatars/guggy.png",
|
||||
description: "Send a reaction GIF using !guggy <query>",
|
||||
simple: true,
|
||||
},
|
||||
// TODO: Support Github
|
||||
// "github": {
|
||||
// name: "Github",
|
||||
// avatarUrl: "/img/avatars/github.png",
|
||||
// avatarUrl: "/assets/img/avatars/github.png",
|
||||
// description: "Github issue management and announcements for a repository",
|
||||
// simple: false,
|
||||
// },
|
||||
"google": {
|
||||
name: "Google",
|
||||
avatarUrl: "/img/avatars/google.png",
|
||||
avatarUrl: "/assets/img/avatars/google.png",
|
||||
description: "Searches Google Images using !google image <query>",
|
||||
simple: true,
|
||||
},
|
||||
"imgur": {
|
||||
name: "Imgur",
|
||||
avatarUrl: "/img/avatars/imgur.png",
|
||||
avatarUrl: "/assets/img/avatars/imgur.png",
|
||||
description: "Searches and posts images from Imgur using !imgur <query>",
|
||||
simple: true,
|
||||
},
|
||||
// TODO: Support JIRA
|
||||
// "jira": {
|
||||
// name: "Jira",
|
||||
// avatarUrl: "/img/avatars/jira.png",
|
||||
// avatarUrl: "/assets/img/avatars/jira.png",
|
||||
// description: "Jira issue management and announcements for a project",
|
||||
// simple: false,
|
||||
// },
|
||||
"rss": {
|
||||
name: "RSS",
|
||||
avatarUrl: "/img/avatars/rssbot.png",
|
||||
avatarUrl: "/assets/img/avatars/rssbot.png",
|
||||
description: "Announces changes to RSS feeds in the room",
|
||||
simple: false,
|
||||
},
|
||||
"travisci": {
|
||||
name: "Travis CI",
|
||||
avatarUrl: "/img/avatars/travisci.png",
|
||||
avatarUrl: "/assets/img/avatars/travisci.png",
|
||||
description: "Announces build results from Travis CI to the room",
|
||||
simple: false,
|
||||
},
|
||||
"wikipedia": {
|
||||
name: "Wikipedia",
|
||||
avatarUrl: "/img/avatars/wikipedia.png",
|
||||
avatarUrl: "/assets/img/avatars/wikipedia.png",
|
||||
description: "Searches wikipedia using !wikipedia <query>",
|
||||
simple: true,
|
||||
},
|
||||
|
30
src/db/migrations/20210809223100-ChangeAvatarUrl.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { QueryInterface } from "sequelize";
|
||||
|
||||
export default {
|
||||
up: (queryInterface: QueryInterface) => {
|
||||
return Promise.resolve()
|
||||
.then(() =>
|
||||
queryInterface.sequelize.query(
|
||||
"UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')"
|
||||
)
|
||||
)
|
||||
.then(() =>
|
||||
queryInterface.sequelize.query(
|
||||
"UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/img/', '/assets/img/')"
|
||||
)
|
||||
);
|
||||
},
|
||||
down: (queryInterface: QueryInterface) => {
|
||||
return Promise.resolve()
|
||||
.then(() =>
|
||||
queryInterface.sequelize.query(
|
||||
"UPDATE dimension_widgets SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')"
|
||||
)
|
||||
)
|
||||
.then(() =>
|
||||
queryInterface.sequelize.query(
|
||||
"UPDATE dimension_bridges SET avatarUrl = REPLACE(avatarUrl, '/assets/img/', '/img/')"
|
||||
)
|
||||
);
|
||||
},
|
||||
};
|
@ -5,7 +5,7 @@ import { Column, Model, PrimaryKey, Table } from "sequelize-typescript";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class AppService extends Model<AppService> {
|
||||
export default class AppService extends Model {
|
||||
@PrimaryKey
|
||||
@Column
|
||||
id: string;
|
||||
|
@ -6,7 +6,7 @@ import AppService from "./AppService";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class AppServiceUser extends Model<AppServiceUser> {
|
||||
export default class AppServiceUser extends Model {
|
||||
@PrimaryKey
|
||||
@Column
|
||||
id: string;
|
||||
|
@ -6,7 +6,7 @@ import { IntegrationRecord } from "./IntegrationRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class CustomSimpleBotRecord extends Model<CustomSimpleBotRecord> implements IntegrationRecord {
|
||||
export default class CustomSimpleBotRecord extends Model implements IntegrationRecord {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import IrcBridgeRecord from "./IrcBridgeRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class IrcBridgeNetwork extends Model<IrcBridgeNetwork> {
|
||||
export default class IrcBridgeNetwork extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class IrcBridgeRecord extends Model<IrcBridgeRecord> {
|
||||
export default class IrcBridgeRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -7,7 +7,7 @@ import NebIntegration from "./NebIntegration";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebBotUser extends Model<NebBotUser> {
|
||||
export default class NebBotUser extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -7,7 +7,7 @@ import AppService from "./AppService";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebConfiguration extends Model<NebConfiguration> {
|
||||
export default class NebConfiguration extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -7,7 +7,7 @@ import NebConfiguration from "./NebConfiguration";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebIntegration extends Model<NebIntegration> implements IntegrationRecord {
|
||||
export default class NebIntegration extends Model implements IntegrationRecord {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import NebIntegration from "./NebIntegration";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebIntegrationConfig extends Model<NebIntegrationConfig> {
|
||||
export default class NebIntegrationConfig extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -8,7 +8,7 @@ import User from "./User";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class NebNotificationUser extends Model<NebNotificationUser> {
|
||||
export default class NebNotificationUser extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class SlackBridgeRecord extends Model<SlackBridgeRecord> {
|
||||
export default class SlackBridgeRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import StickerPack from "./StickerPack";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class Sticker extends Model<Sticker> {
|
||||
export default class Sticker extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import { IntegrationRecord } from "./IntegrationRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class StickerPack extends Model<StickerPack> implements IntegrationRecord {
|
||||
export default class StickerPack extends Model implements IntegrationRecord {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class TelegramBridgeRecord extends Model<TelegramBridgeRecord> {
|
||||
export default class TelegramBridgeRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import TermsTextRecord from "./TermsTextRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class TermsRecord extends Model<TermsRecord> {
|
||||
export default class TermsRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -7,7 +7,7 @@ import TermsRecord from "./TermsRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class TermsSignedRecord extends Model<TermsSignedRecord> {
|
||||
export default class TermsSignedRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -15,7 +15,7 @@ import TermsRecord from "./TermsRecord";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class TermsTextRecord extends Model<TermsTextRecord> {
|
||||
export default class TermsTextRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -15,7 +15,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class TermsUpstreamRecord extends Model<TermsUpstreamRecord> {
|
||||
export default class TermsUpstreamRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -5,7 +5,7 @@ import { AutoIncrement, Column, Model, PrimaryKey, Table } from "sequelize-types
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class Upstream extends Model<Upstream> {
|
||||
export default class Upstream extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -5,7 +5,7 @@ import { Column, Model, PrimaryKey, Table } from "sequelize-typescript";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class User extends Model<User> {
|
||||
export default class User extends Model {
|
||||
// This is really just a holding class to keep foreign keys alive
|
||||
|
||||
@PrimaryKey
|
||||
|
@ -16,7 +16,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class UserScalarToken extends Model<UserScalarToken> {
|
||||
export default class UserScalarToken extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -7,7 +7,7 @@ import User from "./User";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class UserStickerPack extends Model<UserStickerPack> {
|
||||
export default class UserStickerPack extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
@ -6,7 +6,7 @@ import User from "./User";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class Webhook extends Model<Webhook> {
|
||||
export default class Webhook extends Model {
|
||||
// This is really just a holding class to keep foreign keys alive
|
||||
|
||||
@PrimaryKey
|
||||
|
@ -6,7 +6,7 @@ import Upstream from "./Upstream";
|
||||
underscored: false,
|
||||
timestamps: false,
|
||||
})
|
||||
export default class WebhookBridgeRecord extends Model<WebhookBridgeRecord> {
|
||||
export default class WebhookBridgeRecord extends Model {
|
||||
@PrimaryKey
|
||||
@AutoIncrement
|
||||
@Column
|
||||
|
13
src/index.ts
@ -6,6 +6,16 @@ import { CURRENT_VERSION } from "./version";
|
||||
import { MatrixStickerBot } from "./matrix/MatrixStickerBot";
|
||||
import * as BotSdk from "matrix-bot-sdk";
|
||||
import User from "./db/models/User";
|
||||
import { ILoggedInUser } from "./api/security/MatrixSecurity";
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface User extends ILoggedInUser {
|
||||
userId: string;
|
||||
token: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogService.configure(config.logging);
|
||||
LogService.info("index", "Starting dimension " + CURRENT_VERSION);
|
||||
@ -19,7 +29,8 @@ BotSdk.LogService.setLogger({
|
||||
});
|
||||
|
||||
async function startup() {
|
||||
await DimensionStore.updateSchema();
|
||||
const schemas = await DimensionStore.updateSchema();
|
||||
LogService.info("DimensionStore", schemas);
|
||||
|
||||
const webserver = new Webserver();
|
||||
await webserver.start();
|
||||
|
@ -71,7 +71,7 @@ class _MatrixStickerBot {
|
||||
authorName: await this.getUserId(),
|
||||
authorReference: "https://matrix.to/#/" + (await this.getUserId()),
|
||||
license: "Imported",
|
||||
licensePath: "/licenses/general-imported.txt",
|
||||
licensePath: "/assets/licenses/general-imported.txt",
|
||||
trackingRoomAlias: alias,
|
||||
});
|
||||
return this.updateStickersInPacks([pack], roomId);
|
||||
|
@ -7,13 +7,13 @@ class _LicenseMap {
|
||||
public readonly LICENSE_IMPORTED = "Imported";
|
||||
|
||||
private map: { [shortcode: string]: string } = {
|
||||
"Imported": "/licenses/general-imported.txt",
|
||||
"telegram": "/licenses/telegram-imported.txt",
|
||||
"GPL v3.0": "/licenses/gpl-v3.0.txt",
|
||||
"CC BY-NC-SA 4.0": "/licenses/cc_by-nc-sa_4.0.txt",
|
||||
"CC BY-NC 4.0": "/licenses/cc_by-nc_4.0.txt",
|
||||
"CC BY-SA 4.0": "/licenses/cc_by-sa_4.0.txt",
|
||||
"CC BY 4.0": "/licenses/cc_by_4.0.txt",
|
||||
"Imported": "/assets/licenses/general-imported.txt",
|
||||
"telegram": "/assets/licenses/telegram-imported.txt",
|
||||
"GPL v3.0": "/assets/licenses/gpl-v3.0.txt",
|
||||
"CC BY-NC-SA 4.0": "/assets/licenses/cc_by-nc-sa_4.0.txt",
|
||||
"CC BY-NC 4.0": "/assets/licenses/cc_by-nc_4.0.txt",
|
||||
"CC BY-SA 4.0": "/assets/licenses/cc_by-sa_4.0.txt",
|
||||
"CC BY 4.0": "/assets/licenses/cc_by_4.0.txt",
|
||||
};
|
||||
|
||||
public find(name: string): License {
|
||||
|
@ -1,17 +1,19 @@
|
||||
import * as git from "git-rev-sync";
|
||||
import * as child_process from 'child_process';
|
||||
|
||||
let version = "Unknown";
|
||||
let gitHash = null;
|
||||
|
||||
try {
|
||||
version = "v" + require("../../package.json").version;
|
||||
version = "v" + require("../package.json").version;
|
||||
} catch (error) {
|
||||
// The log service isn't set up by the time we require this file
|
||||
console.error("version", error);
|
||||
}
|
||||
|
||||
try {
|
||||
gitHash = git.short();
|
||||
gitHash = child_process
|
||||
.execSync('git rev-parse --short HEAD')
|
||||
.toString().trim()
|
||||
} catch (error) {
|
||||
// The log service isn't set up by the time we require this file
|
||||
console.error("version", error);
|
||||
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"target": "es2015",
|
||||
"noImplicitAny": false,
|
||||
"sourceMap": true,
|
||||
"outDir": "./build/app",
|
||||
"types": [
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
}
|
15
tsconfig.app.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./web",
|
||||
"outDir": "./build/web",
|
||||
"types": ["bluebird", "body-parser", "jquery", "validator"]
|
||||
},
|
||||
"files": [
|
||||
"web/main.ts",
|
||||
"web/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"web/**/*.d.ts"
|
||||
]
|
||||
}
|
18
tsconfig.backend.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./src",
|
||||
"outDir": "./build/app",
|
||||
"types": ["bluebird", "body-parser", "jquery", "validator"],
|
||||
"allowSyntheticDefaultImports": true,
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
],
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,35 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES5",
|
||||
"module": "commonjs",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noEmitHelpers": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"lib": ["es2015", "dom"]
|
||||
},
|
||||
"compileOnSave": false,
|
||||
"buildOnSave": false,
|
||||
"awesomeTypescriptLoaderOptions": {
|
||||
"forkChecker": true,
|
||||
"useWebpackText": true
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./build",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": false, // TODO: Should be fixed
|
||||
"noImplicitAny": false, // TODO: Should be fixed
|
||||
"noImplicitReturns": false, // TODO: Should be fixed
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"downlevelIteration": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2017",
|
||||
"module": "es2020",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictDomEventTypes": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"strictTemplates": true,
|
||||
"types" : ["node"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
16
tsconfig.spec.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": ["jasmine", "bluebird", "body-parser", "jquery", "validator"]
|
||||
},
|
||||
"files": [
|
||||
"web/test.ts",
|
||||
"web/polyfills.ts"
|
||||
],
|
||||
"include": [
|
||||
"web/**/*.spec.ts",
|
||||
"web/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
|
111
tslint.json
@ -1,111 +0,0 @@
|
||||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"comment-format": [
|
||||
true
|
||||
],
|
||||
"curly": false,
|
||||
"eofline": false,
|
||||
"forin": false,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"label-position": true,
|
||||
"max-line-length": false,
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
"static-after-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": false,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": false,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-shadowed-variable": false,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": false,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": false,
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"my",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"my",
|
||||
"kebab-case"
|
||||
],
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true,
|
||||
"pipe-naming": [
|
||||
true,
|
||||
"camelCase",
|
||||
"my"
|
||||
],
|
||||
"no-attribute-parameter-decorator": true,
|
||||
"no-forward-ref": true,
|
||||
"import-destructuring-spacing": true
|
||||
}
|
||||
}
|
@ -2,8 +2,6 @@
|
||||
</header>
|
||||
<main>
|
||||
<toaster-container></toaster-container>
|
||||
<!-- The breadcrumb needs to be defined here otherwise it doesn't work -->
|
||||
<breadcrumb [allowBootstrap]="false" [hidden]="true"></breadcrumb>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
<footer>
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { ApplicationRef, Injector, NgModule } from "@angular/core";
|
||||
import { ModalModule } from "ngx-modialog";
|
||||
import { BootstrapModalModule } from "ngx-modialog/plugins/bootstrap";
|
||||
import { BreadcrumbsModule } from "ng2-breadcrumbs";
|
||||
import { BreadcrumbModule } from "xng-breadcrumb";
|
||||
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
|
||||
import { UiSwitchModule } from "angular2-ui-switch";
|
||||
import { UiSwitchModule } from "ngx-ui-switch";
|
||||
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";
|
||||
import { routing } from "./app.routing";
|
||||
import { FormsModule } from "@angular/forms";
|
||||
@ -120,10 +120,11 @@ import { WhiteboardWidgetComponent } from "./configs/widget/whiteboard/whiteboar
|
||||
import { AdminWidgetWhiteboardConfigComponent } from "./admin/widgets/whiteboard/whiteboard.component";
|
||||
import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
|
||||
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
||||
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
// AoT requires an exported function for factories
|
||||
export function HttpLoaderFactory(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http);
|
||||
return new TranslateHttpLoader(http);
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
@ -140,6 +141,7 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||
BootstrapModalModule,
|
||||
BreadcrumbsModule,
|
||||
CKEditorModule,
|
||||
FontAwesomeModule,
|
||||
TranslateModule.forRoot({
|
||||
loader: {
|
||||
provide: TranslateLoader,
|
||||
@ -288,25 +290,27 @@ export function HttpLoaderFactory(http: HttpClient) {
|
||||
]
|
||||
})
|
||||
export class AppModule {
|
||||
constructor(public appRef: ApplicationRef, injector: Injector) {
|
||||
ServiceLocator.injector = injector;
|
||||
}
|
||||
constructor(public appRef: ApplicationRef, injector: Injector) {
|
||||
ServiceLocator.injector = injector;
|
||||
}
|
||||
|
||||
hmrOnInit(store) {
|
||||
console.log("HMR store", store);
|
||||
}
|
||||
hmrOnInit(store) {
|
||||
console.log("HMR store", store);
|
||||
}
|
||||
|
||||
hmrOnDestroy(store) {
|
||||
let cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
|
||||
// recreate elements
|
||||
store.disposeOldHosts = createNewHosts(cmpLocation);
|
||||
// remove styles
|
||||
removeNgStyles();
|
||||
}
|
||||
hmrOnDestroy(store) {
|
||||
let cmpLocation = this.appRef.components.map(
|
||||
(cmp) => cmp.location.nativeElement
|
||||
);
|
||||
// recreate elements
|
||||
store.disposeOldHosts = createNewHosts(cmpLocation);
|
||||
// remove styles
|
||||
removeNgStyles();
|
||||
}
|
||||
|
||||
hmrAfterDestroy(store) {
|
||||
// display new elements
|
||||
store.disposeOldHosts();
|
||||
delete store.disposeOldHosts;
|
||||
}
|
||||
hmrAfterDestroy(store) {
|
||||
// display new elements
|
||||
store.disposeOldHosts();
|
||||
delete store.disposeOldHosts;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { OnDestroy, OnInit } from "@angular/core";
|
||||
import { Inject, Injectable, Input, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FE_Bridge } from "../../shared/models/integration";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Subscription } from "rxjs/Subscription";
|
||||
@ -8,6 +8,7 @@ import { ServiceLocator } from "../../shared/registry/locator.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
@Injectable()
|
||||
export class BridgeComponent<T> implements OnInit, OnDestroy {
|
||||
|
||||
public isLoading = true;
|
||||
@ -22,7 +23,7 @@ export class BridgeComponent<T> implements OnInit, OnDestroy {
|
||||
protected route = ServiceLocator.injector.get(ActivatedRoute);
|
||||
protected scalarClientApi = ServiceLocator.injector.get(ScalarClientApiService);
|
||||
|
||||
constructor(private integrationType: string, public translate: TranslateService) {
|
||||
constructor(@Inject(String) private integrationType: string, public translate: TranslateService) {
|
||||
this.translate = translate;
|
||||
this.isLoading = true;
|
||||
this.isUpdating = false;
|
||||
|
@ -26,7 +26,7 @@
|
||||
{{'In order to bridge Slack channels, you\'ll need to authorize the bridge to access your teams and channels. Please click the button below to do so.' | translate}}
|
||||
</p>
|
||||
<a [href]="authUrl" rel="noopener" target="_blank">
|
||||
<img src="/img/slack_auth_button.png" class="slack-auth-button" alt="sign in with slack"/>
|
||||
<img src="/assets/img/slack_auth_button.png" class="slack-auth-button" alt="sign in with slack"/>
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="!isBridged && !needsAuth">
|
||||
|
@ -99,11 +99,12 @@ export class TelegramBridgeConfigComponent extends BridgeComponent<TelegramConfi
|
||||
}
|
||||
|
||||
return this.telegram.bridgeRoom(this.roomId, this.bridge.config.portalInfo.chatId, forceUnbridge);
|
||||
}).then((portalInfo: FE_PortalInfo) => {
|
||||
}).then((portalInfo) => {
|
||||
if ((<any>portalInfo).aborted) return;
|
||||
const loadedPortalInfo = portalInfo as FE_PortalInfo
|
||||
|
||||
this.bridge.config.portalInfo = portalInfo;
|
||||
this.bridge.config.linked = [portalInfo.chatId];
|
||||
this.bridge.config.portalInfo = loadedPortalInfo;
|
||||
this.bridge.config.linked = [loadedPortalInfo.chatId];
|
||||
this.isUpdating = false;
|
||||
this.translate.get('Bridge updated').subscribe((res: string) => {this.toaster.pop("success", res); });
|
||||
}).catch(error => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { OnDestroy, OnInit } from "@angular/core";
|
||||
import { Inject, Injectable, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FE_ComplexBot } from "../../shared/models/integration";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Subscription } from "rxjs/Subscription";
|
||||
@ -8,6 +8,7 @@ import { ServiceLocator } from "../../shared/registry/locator.service";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
|
||||
@Injectable()
|
||||
export class ComplexBotComponent<T> implements OnInit, OnDestroy {
|
||||
|
||||
public isLoading = true;
|
||||
@ -23,7 +24,8 @@ export class ComplexBotComponent<T> implements OnInit, OnDestroy {
|
||||
protected route = ServiceLocator.injector.get(ActivatedRoute);
|
||||
protected scalarClientApi = ServiceLocator.injector.get(ScalarClientApiService);
|
||||
|
||||
constructor(private integrationType: string, public translate: TranslateService) {
|
||||
constructor(@Inject(String) private integrationType: string, public translate: TranslateService) {
|
||||
this.translate = translate;
|
||||
this.isLoading = true;
|
||||
this.isUpdating = false;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
<my-spinner></my-spinner>
|
||||
</div>
|
||||
<div *ngIf="!widgetComponent.isLoading">
|
||||
<my-ibox [isCollapsible]="true" [defaultCollapsed]="widgetComponent.defaultExpandedWidgetId">
|
||||
<my-ibox [isCollapsible]="true" [defaultCollapsed]="!!widgetComponent.defaultExpandedWidgetId">
|
||||
<h5 class="my-ibox-title">
|
||||
<i class="far fa-plus-square"></i> {{ widgetComponent.defaultName | translate }} {{'Add' | translate}}
|
||||
</h5>
|
||||
|
@ -3,8 +3,8 @@ import { ToasterService } from "angular2-toaster";
|
||||
import { ScalarClientApiService } from "../../shared/services/scalar/scalar-client-api.service";
|
||||
import { ServiceLocator } from "../../shared/registry/locator.service";
|
||||
import { SessionStorage } from "../../shared/SessionStorage";
|
||||
import { OnInit } from "@angular/core";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { Inject, Injectable, OnInit } from "@angular/core";
|
||||
|
||||
const SCALAR_WIDGET_LINKS = [
|
||||
"https://scalar-staging.riot.im/scalar/api/widgets/__TYPE__.html?__PNAME__=",
|
||||
@ -16,6 +16,7 @@ const SCALAR_WIDGET_LINKS = [
|
||||
|
||||
export const DISABLE_AUTOMATIC_WRAPPING = "";
|
||||
|
||||
@Injectable()
|
||||
export class WidgetComponent implements OnInit {
|
||||
|
||||
public isLoading = true;
|
||||
@ -31,13 +32,14 @@ export class WidgetComponent implements OnInit {
|
||||
private window = ServiceLocator.injector.get(Window);
|
||||
private scalarApi = ServiceLocator.injector.get(ScalarClientApiService);
|
||||
|
||||
constructor(private widgetTypes: string[],
|
||||
public defaultName: string,
|
||||
private wrapperId = "generic",
|
||||
constructor(@Inject(String) private widgetTypes: string[],
|
||||
@Inject(String) public defaultName: string,
|
||||
@Inject(String) private wrapperId = "generic",
|
||||
public translate: TranslateService,
|
||||
private scalarWrapperId = null,
|
||||
private scalarWrapperUrlParamName = "url") {
|
||||
@Inject(String) private scalarWrapperId = null,
|
||||
@Inject(String) private scalarWrapperUrlParamName = "url") {
|
||||
this.translate = translate;
|
||||
|
||||
this.isLoading = true;
|
||||
this.isUpdating = false;
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
<button myToggleFullscreen="">
|
||||
<img [src]="isFullscreen ? '/img/exit-fullscreen.png' : '/img/enter-fullscreen.png'"/>
|
||||
<img [src]="isFullscreen ? '/assets/img/exit-fullscreen.png' : '/assets/img/enter-fullscreen.png'"/>
|
||||
</button>
|
@ -1,4 +1,4 @@
|
||||
// component styles are encapsulated and only applied to their components
|
||||
@import "../../../../node_modules/spinkit/scss/spinners/11-folding-cube";
|
||||
@import "../../../../node_modules/spinkit/spinkit.min.css";
|
||||
|
||||
// see app.scss for the spinner color stuff
|
@ -1,6 +1,6 @@
|
||||
<div *ngIf="showPromoPage" class="promo">
|
||||
<div class="hero">
|
||||
<img src="/img/logo/banner-sm.png" class="logo">
|
||||
<img src="/assets/img/logo/banner-sm.png" class="logo">
|
||||
<h1>{{'An open source integration manager for Matrix' | translate}}</h1>
|
||||
<div class="banner">
|
||||
{{'Self-host your favourite bots, bridges, and widgets.' | translate}}
|
||||
@ -22,7 +22,7 @@
|
||||
<pre>{{ integrationsConfig }}</pre>
|
||||
</div>
|
||||
<div class="screenshot shadowed">
|
||||
<img src="/img/screenshot.png">
|
||||
<img src="/assets/img/screenshot.png">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -34,52 +34,52 @@
|
||||
|
||||
<div class="integration-list">
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/jitsi.png">
|
||||
<span></span>
|
||||
<img src="/assets/img/avatars/jitsi.png">
|
||||
<span>Jitsi</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/etherpad.png">
|
||||
<img src="/assets/img/avatars/etherpad.png">
|
||||
<span>{{'Notes' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/tradingview.png">
|
||||
<span></span>
|
||||
<img src="/assets/img/avatars/tradingview.png">
|
||||
<span>TradingView</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/spotify.png">
|
||||
<img src="/assets/img/avatars/spotify.png">
|
||||
<span>Spotify</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/youtube.png">
|
||||
<img src="/assets/img/avatars/youtube.png">
|
||||
<span>YouTube</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/twitch.png">
|
||||
<img src="/assets/img/avatars/twitch.png">
|
||||
<span>Twitch Livestream</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/grafana.png">
|
||||
<img src="/assets/img/avatars/grafana.png">
|
||||
<span>Grafana</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/googledocs.png">
|
||||
<img src="/assets/img/avatars/googledocs.png">
|
||||
<span>Google Docs</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/googlecalendar.png">
|
||||
<img src="/assets/img/avatars/googlecalendar.png">
|
||||
<span>{{'Google Calendar' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/bigbluebutton.png">
|
||||
<img src="/assets/img/avatars/bigbluebutton.png">
|
||||
<span>BigBlueButton</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/customwidget.png">
|
||||
<span>{{'Custom Widget' | translate}}</span>
|
||||
<img src="/assets/img/avatars/whiteboard.png">
|
||||
<span>Whiteboard</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/whiteboard.png">
|
||||
<span>Whiteboard</span>
|
||||
<img src="/assets/img/avatars/customwidget.png">
|
||||
<span>{{'Custom Widget' | translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -92,51 +92,51 @@
|
||||
|
||||
<div class="integration-list">
|
||||
<!--<div class="integration">-->
|
||||
<!--<img src="/img/avatars/github.png">-->
|
||||
<!--<img src="/assets/img/avatars/github.png">-->
|
||||
<!--<span>GitHub</span>-->
|
||||
<!--</div>-->
|
||||
<!--<div class="integration">-->
|
||||
<!--<img src="/img/avatars/jira.png">-->
|
||||
<!--<img src="/assets/img/avatars/jira.png">-->
|
||||
<!--<span>Jira</span>-->
|
||||
<!--</div>-->
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/guggy.png">
|
||||
<img src="/assets/img/avatars/guggy.png">
|
||||
<span>{{'Guggy' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/giphy.png">
|
||||
<img src="/assets/img/avatars/giphy.png">
|
||||
<span>{{'Giphy' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/imgur.png">
|
||||
<img src="/assets/img/avatars/imgur.png">
|
||||
<span>{{'Imgur' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/google.png">
|
||||
<img src="/assets/img/avatars/google.png">
|
||||
<span>{{'Google Image Search' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/wikipedia.png">
|
||||
<img src="/assets(img/avatars/wikipedia.png">
|
||||
<span>{{'Wikipedia' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/travisci.png">
|
||||
<img src="/assets/img/avatars/travisci.png">
|
||||
<span>{{'Travis CI' | translate}}</span>
|
||||
</div>
|
||||
<!--<div class="integration">-->
|
||||
<!--<img src="/img/avatars/circleci.png">-->
|
||||
<!--<img src="/assets/img/avatars/circleci.png">-->
|
||||
<!--<span>Circle CI</span>-->
|
||||
<!--</div>-->
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/rssbot.png">
|
||||
<img src="/assets/img/avatars/rssbot.png">
|
||||
<span>{{'RSS Notifications' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/echo.png">
|
||||
<img src="/assets/img/avatars/echo.png">
|
||||
<span>{{'Echo' | translate}}</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/custombots.png">
|
||||
<img src="/assets/img/avatars/custombots.png">
|
||||
<span>{{'Custom Bots' | translate}}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -150,23 +150,23 @@
|
||||
|
||||
<div class="integration-list">
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/irc.png">
|
||||
<img src="/assets/img/avatars/irc.png">
|
||||
<span>IRC</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/telegram.png">
|
||||
<img src="/assets/img/avatars/telegram.png">
|
||||
<span>Telegram</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/gitter.png">
|
||||
<img src="/assets/img/avatars/gitter.png">
|
||||
<span>Gitter</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/slack.png">
|
||||
<img src="/assets/img/avatars/slack.png">
|
||||
<span>Slack</span>
|
||||
</div>
|
||||
<div class="integration">
|
||||
<img src="/img/avatars/webhooks.png">
|
||||
<img src="/assets/img/avatars/webhooks.png">
|
||||
<span>Webhooks</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -204,7 +204,7 @@
|
||||
<div class="footer">
|
||||
<a href="https://github.com/turt2live/matrix-dimension" target="_blank">{{'source on GitHub' | translate}}</a>
|
||||
<a href="https://matrix.org" target="_blank" class="made-for-matrix-anchor">
|
||||
<img src="/img/logo/made-for-matrix.svg" class="made-for-matrix">
|
||||
<img src="/assets/img/logo/made-for-matrix.svg" class="made-for-matrix">
|
||||
</a>
|
||||
<a href="https://matrix.to/#/#dimension:t2bot.io">#dimension:t2bot.io</a>
|
||||
</div>
|
||||
@ -212,7 +212,7 @@
|
||||
|
||||
<div *ngIf="!showPromoPage" class="non-promo">
|
||||
<div class="hero">
|
||||
<img src="/img/logo/banner-sm.png" class="logo">
|
||||
<img src="/assets/img/logo/banner-sm.png" class="logo">
|
||||
<div class="links">
|
||||
<a href="https://github.com/turt2live/matrix-dimension" target="_blank">{{'source' | translate}}</a>
|
||||
<a href="https://matrix.to/#/#dimension:t2bot.io">#dimension:t2bot.io</a>
|
||||
@ -261,7 +261,7 @@
|
||||
<div class="footer">
|
||||
<a href="https://github.com/turt2live/matrix-dimension" target="_blank">{{'source on GitHub' | translate}}</a>
|
||||
<a href="https://matrix.org" target="_blank" class="made-for-matrix-anchor">
|
||||
<img src="/img/logo/made-for-matrix.svg" class="made-for-matrix">
|
||||
<img src="/assets/img/logo/made-for-matrix.svg" class="made-for-matrix">
|
||||
</a>
|
||||
<a href="https://matrix.to/#/#dimension:t2bot.io">#dimension:t2bot.io</a>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<div class="header">
|
||||
<div class="title">
|
||||
<h2 class="pageName">{{ pageName | translate }}</h2>
|
||||
<breadcrumb [allowBootstrap]="true" class="dimension-breadcrumb"></breadcrumb>
|
||||
<xng-breadcrumb></xng-breadcrumb>
|
||||
</div>
|
||||
<div class="quickAction">
|
||||
<ng-content></ng-content>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { ActivatedRoute, NavigationEnd, PRIMARY_OUTLET, Router } from "@angular/router";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { filter } from "rxjs/operators";
|
||||
|
||||
@Component({
|
||||
selector: "my-page-header",
|
||||
@ -13,12 +14,13 @@ export class PageHeaderComponent {
|
||||
|
||||
constructor(private router: Router, private activatedRoute: ActivatedRoute, public translate: TranslateService) {
|
||||
this.translate = translate;
|
||||
this.router.events.filter(ev => ev instanceof NavigationEnd).subscribe((ev: NavigationEnd) => {
|
||||
this.router.events.pipe(filter(ev => ev instanceof NavigationEnd)).subscribe((ev) => {
|
||||
let currentRoute = this.activatedRoute.root;
|
||||
let url = "";
|
||||
const event = ev as NavigationEnd;
|
||||
|
||||
while (currentRoute.children.length > 0) {
|
||||
let children = currentRoute.children;
|
||||
const children = currentRoute.children;
|
||||
children.forEach(route => {
|
||||
if (route.snapshot.data['breadcrumb']) {
|
||||
this.translate.get(route.snapshot.data['breadcrumb']).subscribe((res: string) => {route.snapshot.data['breadcrumb'] = res});
|
||||
@ -27,7 +29,7 @@ export class PageHeaderComponent {
|
||||
url += "/" + route.snapshot.url.map(s => s.path).join("/");
|
||||
if (route.outlet !== PRIMARY_OUTLET) return;
|
||||
if (!route.routeConfig || !route.routeConfig.data) return;
|
||||
if (url === ev.urlAfterRedirects.split("?")[0]) this.pageName = route.snapshot.data.name;
|
||||
if (url === event.urlAfterRedirects.split("?")[0]) this.pageName = route.snapshot.data.name;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ export class ToggleFullscreenDirective {
|
||||
onClick() {
|
||||
// HACK: This should be behind a service in the event the library changes
|
||||
// @ts-ignore
|
||||
if (screenfull.enabled) {
|
||||
if (screenfull.isEnabled) {
|
||||
// @ts-ignore
|
||||
screenfull.toggle();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { FE_Integration } from "./integration";
|
||||
export interface FE_DimensionConfig {
|
||||
admins: string[];
|
||||
widgetBlacklist: string[];
|
||||
homesever: {
|
||||
homeserver: {
|
||||
name: string;
|
||||
userId: string;
|
||||
federationUrl: string;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { OnDestroy, OnInit } from "@angular/core";
|
||||
import { Injectable, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Subscription } from "rxjs/Subscription";
|
||||
import { ScalarWidgetApi } from "../shared/services/scalar/scalar-widget.api";
|
||||
import * as semver from "semver";
|
||||
@ -14,11 +14,12 @@ export interface OpenIdResponse {
|
||||
blocked: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export abstract class CapableWidget implements OnInit, OnDestroy {
|
||||
|
||||
private requestSubscription: Subscription;
|
||||
private responseSubscription: Subscription;
|
||||
private openIdRequest: { resolve: (a: OpenIdResponse) => void, promise: Promise<OpenIdResponse> } = null;
|
||||
private openIdRequest: { resolve: (a: OpenIdResponse) => void } = null;
|
||||
|
||||
// The capabilities we support
|
||||
protected supportsScreenshots = false;
|
||||
@ -92,9 +93,8 @@ export abstract class CapableWidget implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
protected getOpenIdInfo(): Promise<OpenIdResponse> {
|
||||
if (this.openIdRequest) return this.openIdRequest.promise;
|
||||
const promise = new Promise<OpenIdResponse>(((resolve, _reject) => {
|
||||
this.openIdRequest = {resolve: resolve, promise};
|
||||
this.openIdRequest = {resolve: resolve};
|
||||
ScalarWidgetApi.requestOpenID();
|
||||
}));
|
||||
return promise;
|
||||
|
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="no-stickers" *ngIf="!isLoading && !authError && (!packs || packs.length === 0)">
|
||||
<img src="/img/no_stickers.png"/>
|
||||
<img src="/assets/img/no_stickers.png"/>
|
||||
<span class="message">{{'You have no sticker packs.' | translate}}</span>
|
||||
<button class="btn btn-link btn-sm" (click)="openIntegrationManager()">{{'Add some stickers' | translate}}</button>
|
||||
</div>
|
||||
|
6
web/assets/fonts/opensans100-roboto300.scss
Normal file
@ -0,0 +1,6 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Roboto Light'), local('Roboto-Light'), url('./opensans100-roboto300.ttf') format('truetype');
|
||||
}
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
web/assets/img/avatars/gitter.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |