Reorganize project. Add folder for shared code between backend/dashboard. Switch from jest to ava for tests.

This commit is contained in:
Dragory 2019-11-02 22:11:26 +02:00
parent 80a82fe348
commit 16111bbe84
162 changed files with 11056 additions and 9900 deletions

12
.gitignore vendored
View file

@ -63,20 +63,12 @@ typings/
# windows folder options # windows folder options
desktop.ini desktop.ini
# Knub data
/data
/config
# PHPStorm # PHPStorm
.idea/ .idea/
# Compiled files
/dist
/dist-frontend
# Misc # Misc
/convert.js /convert.js
/startscript.js /startscript.js
/.cache /.cache
/npm-ls.txt npm-ls.txt
/npm-audit.txt npm-audit.txt

View file

@ -1,6 +0,0 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript'
]
};

3
backend/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/.cache
/dist
/node_modules

6866
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

83
backend/package.json Normal file
View file

@ -0,0 +1,83 @@
{
"name": "@zeppelin/backend",
"version": "0.0.1",
"description": "",
"private": true,
"scripts": {
"start-bot-dev": "node -r ts-node/register src/index.ts",
"start-bot-prod": "cross-env NODE_ENV=production node dist/index.js",
"watch-bot": "nodemon --config nodemon-bot.json",
"build": "rimraf dist && tsc",
"start-api-dev": "node -r ts-node/register src/api/index.ts",
"start-api-prod": "cross-env NODE_ENV=production node dist/api/index.js",
"watch-api": "nodemon --config nodemon-api.json",
"format": "prettier --write \"./src/**/*.ts\"",
"typeorm": "node -r ts-node/register ./node_modules/typeorm/cli.js",
"migrate": "npm run typeorm -- migration:run",
"migrate-rollback": "npm run typeorm -- migration:revert",
"test": "ava"
},
"dependencies": {
"cors": "^2.8.5",
"cross-env": "^5.2.0",
"deep-diff": "^1.0.2",
"dotenv": "^4.0.0",
"emoji-regex": "^8.0.0",
"eris": "^0.11.0",
"escape-string-regexp": "^1.0.5",
"express": "^4.17.0",
"fp-ts": "^2.0.1",
"humanize-duration": "^3.15.0",
"io-ts": "^2.0.0",
"js-yaml": "^3.13.1",
"knub": "^26.0.2",
"knub-command-manager": "^6.1.0",
"last-commit-log": "^2.1.0",
"lodash.chunk": "^4.2.0",
"lodash.clonedeep": "^4.5.0",
"lodash.difference": "^4.5.0",
"lodash.intersection": "^4.4.0",
"lodash.isequal": "^4.5.0",
"lodash.pick": "^4.4.0",
"moment-timezone": "^0.5.21",
"mysql": "^2.16.0",
"passport": "^0.4.0",
"passport-custom": "^1.0.5",
"passport-oauth2": "^1.5.0",
"reflect-metadata": "^0.1.12",
"safe-regex": "^2.0.2",
"seedrandom": "^3.0.1",
"tlds": "^1.203.1",
"tmp": "0.0.33",
"typeorm": "^0.2.14",
"uuid": "^3.3.2"
},
"devDependencies": {
"@types/cors": "^2.8.5",
"@types/express": "^4.16.1",
"@types/jest": "^24.0.15",
"@types/js-yaml": "^3.12.1",
"@types/lodash.at": "^4.6.3",
"@types/moment-timezone": "^0.5.6",
"@types/node": "^12.7.5",
"@types/passport": "^1.0.0",
"@types/passport-oauth2": "^1.4.8",
"@types/passport-strategy": "^0.2.35",
"@types/tmp": "0.0.33",
"ava": "^2.4.0",
"nodemon": "^1.19.4",
"rimraf": "^2.6.2",
"ts-node": "^8.4.1",
"typescript": "^3.6.4"
},
"ava": {
"compileEnhancements": false,
"files": [
"src/**/*.test.ts"
],
"extensions": ["ts"],
"require": [
"ts-node/register"
]
}
}

View file

@ -1,7 +1,7 @@
import express, { Request, Response } from "express"; import express, { Request, Response } from "express";
import passport from "passport"; import passport, { Strategy } from "passport";
import OAuth2Strategy from "passport-oauth2"; import OAuth2Strategy from "passport-oauth2";
import CustomStrategy from "passport-custom"; import { Strategy as CustomStrategy } from "passport-custom";
import { ApiLogins } from "../data/ApiLogins"; import { ApiLogins } from "../data/ApiLogins";
import pick from "lodash.pick"; import pick from "lodash.pick";
import https from "https"; import https from "https";
@ -10,6 +10,18 @@ import { ApiUserInfoData } from "../data/entities/ApiUserInfo";
import { ApiPermissions } from "../data/ApiPermissions"; import { ApiPermissions } from "../data/ApiPermissions";
import { ok } from "./responses"; import { ok } from "./responses";
interface IPassportApiUser {
apiKey: string;
userId: number;
}
declare global {
namespace Express {
// tslint:disable-next-line:no-empty-interface
interface User extends IPassportApiUser {}
}
}
const DISCORD_API_URL = "https://discordapp.com/api"; const DISCORD_API_URL = "https://discordapp.com/api";
function simpleDiscordAPIRequest(bearerToken, path): Promise<any> { function simpleDiscordAPIRequest(bearerToken, path): Promise<any> {
@ -66,14 +78,14 @@ export function initAuth(app: express.Express) {
"api-token", "api-token",
new CustomStrategy(async (req, cb) => { new CustomStrategy(async (req, cb) => {
const apiKey = req.header("X-Api-Key"); const apiKey = req.header("X-Api-Key");
if (!apiKey) return cb(); if (!apiKey) return cb("API key missing");
const userId = await apiLogins.getUserIdByApiKey(apiKey); const userId = await apiLogins.getUserIdByApiKey(apiKey);
if (userId) { if (userId) {
return cb(null, { apiKey, userId }); return cb(null, { apiKey, userId });
} }
cb(); cb("API key not found");
}), }),
); );
@ -113,7 +125,7 @@ export function initAuth(app: express.Express) {
app.get( app.get(
"/auth/oauth-callback", "/auth/oauth-callback",
passport.authenticate("oauth2", { failureRedirect: "/", session: false }), passport.authenticate("oauth2", { failureRedirect: "/", session: false }),
(req, res) => { (req: Request, res: Response) => {
if (req.user && req.user.apiKey) { if (req.user && req.user.apiKey) {
res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?apiKey=${req.user.apiKey}`); res.redirect(`${process.env.DASHBOARD_URL}/login-callback/?apiKey=${req.user.apiKey}`);
} else { } else {
@ -143,7 +155,7 @@ export function initAuth(app: express.Express) {
export function apiTokenAuthHandlers() { export function apiTokenAuthHandlers() {
return [ return [
passport.authenticate("api-token", { failWithError: true }), passport.authenticate("api-token", { failWithError: true }),
(err, req, res, next) => { (err, req: Request, res: Response, next) => {
return res.json({ error: err.message }); return res.json({ error: err.message });
}, },
]; ];

View file

@ -8,5 +8,5 @@ export const CaseTypeColors = {
[CaseTypes.Kick]: 0xe67e22, [CaseTypes.Kick]: 0xe67e22,
[CaseTypes.Softban]: 0xe67e22, [CaseTypes.Softban]: 0xe67e22,
[CaseTypes.Ban]: 0xcb4314, [CaseTypes.Ban]: 0xcb4314,
[CaseTypes.Unban]: 0x9b59b6 [CaseTypes.Unban]: 0x9b59b6,
}; };

View file

@ -111,7 +111,7 @@ const zalgoChars = [
"\u0356", "\u0356",
"\u0359", "\u0359",
"\u035a", "\u035a",
"\u0323" "\u0323",
]; ];
export const ZalgoRegex = new RegExp(zalgoChars.join("|")); export const ZalgoRegex = new RegExp(zalgoChars.join("|"));

View file

@ -1,3 +1,4 @@
// tslint:disable:no-console
import { connect } from "./data/db"; import { connect } from "./data/db";
import { Configs } from "./data/Configs"; import { Configs } from "./data/Configs";
import path from "path"; import path from "path";

View file

@ -10,48 +10,48 @@ export class CreateMessagesTable1543053430712 implements MigrationInterface {
name: "id", name: "id",
type: "bigint", type: "bigint",
unsigned: true, unsigned: true,
isPrimary: true isPrimary: true,
}, },
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "user_id", name: "user_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "is_bot", name: "is_bot",
type: "tinyint", type: "tinyint",
unsigned: true unsigned: true,
}, },
{ {
name: "data", name: "data",
type: "mediumtext" type: "mediumtext",
}, },
{ {
name: "posted_at", name: "posted_at",
type: "datetime(3)" type: "datetime(3)",
}, },
{ {
name: "deleted_at", name: "deleted_at",
type: "datetime(3)", type: "datetime(3)",
isNullable: true, isNullable: true,
default: null default: null,
}, },
{ {
name: "is_permanent", name: "is_permanent",
type: "tinyint", type: "tinyint",
unsigned: true, unsigned: true,
default: 0 default: 0,
} },
], ],
indices: [ indices: [
{ columnNames: ["guild_id"] }, { columnNames: ["guild_id"] },
@ -60,9 +60,9 @@ export class CreateMessagesTable1543053430712 implements MigrationInterface {
{ columnNames: ["is_bot"] }, { columnNames: ["is_bot"] },
{ columnNames: ["posted_at"] }, { columnNames: ["posted_at"] },
{ columnNames: ["deleted_at"] }, { columnNames: ["deleted_at"] },
{ columnNames: ["is_permanent"] } { columnNames: ["is_permanent"] },
] ],
}) }),
); );
} }

View file

@ -9,21 +9,21 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "slowmode_seconds", name: "slowmode_seconds",
type: "int", type: "int",
unsigned: true unsigned: true,
} },
], ],
indices: [] indices: [],
}) }),
); );
await queryRunner.createPrimaryKey("slowmode_channels", ["guild_id", "channel_id"]); await queryRunner.createPrimaryKey("slowmode_channels", ["guild_id", "channel_id"]);
@ -34,29 +34,29 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "user_id", name: "user_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "expires_at", name: "expires_at",
type: "datetime" type: "datetime",
} },
], ],
indices: [ indices: [
{ {
columnNames: ["expires_at"] columnNames: ["expires_at"],
} },
] ],
}) }),
); );
await queryRunner.createPrimaryKey("slowmode_users", ["guild_id", "channel_id", "user_id"]); await queryRunner.createPrimaryKey("slowmode_users", ["guild_id", "channel_id", "user_id"]);
} }
@ -64,7 +64,7 @@ export class CreateSlowmodeTables1544877081073 implements MigrationInterface {
public async down(queryRunner: QueryRunner): Promise<any> { public async down(queryRunner: QueryRunner): Promise<any> {
await Promise.all([ await Promise.all([
queryRunner.dropTable("slowmode_channels", true), queryRunner.dropTable("slowmode_channels", true),
queryRunner.dropTable("slowmode_users", true) queryRunner.dropTable("slowmode_users", true),
]); ]);
} }
} }

View file

@ -12,45 +12,45 @@ export class CreateStarboardTable1544887946307 implements MigrationInterface {
unsigned: true, unsigned: true,
isGenerated: true, isGenerated: true,
generationStrategy: "increment", generationStrategy: "increment",
isPrimary: true isPrimary: true,
}, },
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_whitelist", name: "channel_whitelist",
type: "text", type: "text",
isNullable: true, isNullable: true,
default: null default: null,
}, },
{ {
name: "emoji", name: "emoji",
type: "varchar", type: "varchar",
length: "64" length: "64",
}, },
{ {
name: "reactions_required", name: "reactions_required",
type: "smallint", type: "smallint",
unsigned: true unsigned: true,
} },
], ],
indices: [ indices: [
{ {
columnNames: ["guild_id", "emoji"] columnNames: ["guild_id", "emoji"],
}, },
{ {
columnNames: ["guild_id", "channel_id"], columnNames: ["guild_id", "channel_id"],
isUnique: true isUnique: true,
} },
] ],
}) }),
); );
await queryRunner.createTable( await queryRunner.createTable(
@ -60,20 +60,20 @@ export class CreateStarboardTable1544887946307 implements MigrationInterface {
{ {
name: "starboard_id", name: "starboard_id",
type: "int", type: "int",
unsigned: true unsigned: true,
}, },
{ {
name: "message_id", name: "message_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "starboard_message_id", name: "starboard_message_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
} },
] ],
}) }),
); );
await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]); await queryRunner.createPrimaryKey("starboard_messages", ["starboard_id", "message_id"]);
} }

View file

@ -12,44 +12,44 @@ export class CreateTagResponsesTable1546770935261 implements MigrationInterface
unsigned: true, unsigned: true,
isGenerated: true, isGenerated: true,
generationStrategy: "increment", generationStrategy: "increment",
isPrimary: true isPrimary: true,
}, },
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "command_message_id", name: "command_message_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "response_message_id", name: "response_message_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
} },
], ],
indices: [ indices: [
{ {
columnNames: ["guild_id"] columnNames: ["guild_id"],
} },
], ],
foreignKeys: [ foreignKeys: [
{ {
columnNames: ["command_message_id"], columnNames: ["command_message_id"],
referencedTableName: "messages", referencedTableName: "messages",
referencedColumnNames: ["id"], referencedColumnNames: ["id"],
onDelete: "CASCADE" onDelete: "CASCADE",
}, },
{ {
columnNames: ["response_message_id"], columnNames: ["response_message_id"],
referencedTableName: "messages", referencedTableName: "messages",
referencedColumnNames: ["id"], referencedColumnNames: ["id"],
onDelete: "CASCADE" onDelete: "CASCADE",
} },
] ],
}) }),
); );
} }

View file

@ -12,47 +12,47 @@ export class CreateNameHistoryTable1546778415930 implements MigrationInterface {
unsigned: true, unsigned: true,
isGenerated: true, isGenerated: true,
generationStrategy: "increment", generationStrategy: "increment",
isPrimary: true isPrimary: true,
}, },
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "user_id", name: "user_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "type", name: "type",
type: "tinyint", type: "tinyint",
unsigned: true unsigned: true,
}, },
{ {
name: "value", name: "value",
type: "varchar", type: "varchar",
length: "128", length: "128",
isNullable: true isNullable: true,
}, },
{ {
name: "timestamp", name: "timestamp",
type: "datetime", type: "datetime",
default: "CURRENT_TIMESTAMP" default: "CURRENT_TIMESTAMP",
} },
], ],
indices: [ indices: [
{ {
columnNames: ["guild_id", "user_id"] columnNames: ["guild_id", "user_id"],
}, },
{ {
columnNames: ["type"] columnNames: ["type"],
}, },
{ {
columnNames: ["timestamp"] columnNames: ["timestamp"],
} },
] ],
}) }),
); );
} }

View file

@ -9,19 +9,19 @@ export class CreateAutoReactionsTable1547290549908 implements MigrationInterface
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "reactions", name: "reactions",
type: "text" type: "text",
} },
] ],
}) }),
); );
await queryRunner.createPrimaryKey("auto_reactions", ["guild_id", "channel_id"]); await queryRunner.createPrimaryKey("auto_reactions", ["guild_id", "channel_id"]);
} }

View file

@ -12,34 +12,34 @@ export class CreatePingableRolesTable1547293464842 implements MigrationInterface
unsigned: true, unsigned: true,
isGenerated: true, isGenerated: true,
generationStrategy: "increment", generationStrategy: "increment",
isPrimary: true isPrimary: true,
}, },
{ {
name: "guild_id", name: "guild_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "channel_id", name: "channel_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
}, },
{ {
name: "role_id", name: "role_id",
type: "bigint", type: "bigint",
unsigned: true unsigned: true,
} },
], ],
indices: [ indices: [
{ {
columnNames: ["guild_id", "channel_id"] columnNames: ["guild_id", "channel_id"],
}, },
{ {
columnNames: ["guild_id", "channel_id", "role_id"], columnNames: ["guild_id", "channel_id", "role_id"],
isUnique: true isUnique: true,
} },
] ],
}) }),
); );
} }

View file

@ -5,8 +5,8 @@ export class AddIndexToArchivesExpiresAt1547392046629 implements MigrationInterf
await queryRunner.createIndex( await queryRunner.createIndex(
"archives", "archives",
new TableIndex({ new TableIndex({
columnNames: ["expires_at"] columnNames: ["expires_at"],
}) }),
); );
} }
@ -14,8 +14,8 @@ export class AddIndexToArchivesExpiresAt1547392046629 implements MigrationInterf
await queryRunner.dropIndex( await queryRunner.dropIndex(
"archives", "archives",
new TableIndex({ new TableIndex({
columnNames: ["expires_at"] columnNames: ["expires_at"],
}) }),
); );
} }
} }

View file

@ -8,14 +8,14 @@ export class AddIsHiddenToCases1547393619900 implements MigrationInterface {
name: "is_hidden", name: "is_hidden",
type: "tinyint", type: "tinyint",
unsigned: true, unsigned: true,
default: 0 default: 0,
}) }),
); );
await queryRunner.createIndex( await queryRunner.createIndex(
"cases", "cases",
new TableIndex({ new TableIndex({
columnNames: ["is_hidden"] columnNames: ["is_hidden"],
}) }),
); );
} }

Some files were not shown because too many files have changed in this diff Show more