mirror of
https://github.com/spacebarchat/server.git
synced 2024-11-08 11:52:55 +01:00
Refactor to mono-repo + upgrade packages
This commit is contained in:
parent
59d94b4894
commit
f44f5d7ac2
@ -1,5 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*.ts]
|
|
||||||
indent_style = tab
|
|
||||||
indent_size = 4
|
|
@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 4,
|
|
||||||
"useTabs": true,
|
|
||||||
"printWidth": 140,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"useTabs": true
|
|
||||||
}
|
|
22
Dockerfile
22
Dockerfile
@ -1,22 +0,0 @@
|
|||||||
FROM node:alpine
|
|
||||||
|
|
||||||
# env vars
|
|
||||||
ENV HTTP_PORT=3001
|
|
||||||
ENV WS_PORT=3002
|
|
||||||
ENV CDN_PORT=3003
|
|
||||||
ENV RTC_PORT=3004
|
|
||||||
ENV ADMIN_PORT=3005
|
|
||||||
|
|
||||||
# exposed ports (only for reference, see https://docs.docker.com/engine/reference/builder/#expose)
|
|
||||||
EXPOSE ${HTTP_PORT}/tcp ${WS_PORT}/tcp ${CDN_PORT}/tcp ${RTC_PORT}/tcp ${ADMIN_PORT}/tcp
|
|
||||||
|
|
||||||
# install required apps
|
|
||||||
RUN apk add --no-cache --update git python3 py-pip make build-base
|
|
||||||
RUN ln -s /usr/bin/python3 /usr/bin/python
|
|
||||||
|
|
||||||
# Run as non-root user
|
|
||||||
# RUN adduser -D fosscord
|
|
||||||
# USER fosscord
|
|
||||||
|
|
||||||
WORKDIR /srv/fosscord-server/bundle
|
|
||||||
ENTRYPOINT ["npm", "run", "start:bundle"]
|
|
@ -1,2 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
@ -1,8 +0,0 @@
|
|||||||
MONGO_URL=mongodb://localhost/fosscord
|
|
||||||
PORT=3001
|
|
||||||
PRODUCTION=TRUE
|
|
||||||
THREADS=# automatically use all available cores, only available if production = true
|
|
||||||
#LOG_REQUESTS=
|
|
||||||
# only log 200 and 204: LOG_REQUESTS=200 204
|
|
||||||
# log everything except 200 and 204: LOG_REQUESTS=-200 204
|
|
||||||
# log all requests: LOG_REQUESTS=-
|
|
115
api/.gitignore
vendored
115
api/.gitignore
vendored
@ -1,115 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
|
||||||
jspm_packages/
|
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
|
||||||
typings/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
.env.test
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
|
||||||
build
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
.DS_STORE
|
|
||||||
src/ready.json
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
.docker/config/*
|
|
||||||
!.docker/config/.keep
|
|
||||||
|
|
||||||
# fosscord
|
|
||||||
*.db
|
|
@ -1 +0,0 @@
|
|||||||
!dist/
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 4,
|
|
||||||
"useTabs": true,
|
|
||||||
"printWidth": 140,
|
|
||||||
"trailingComma": "none"
|
|
||||||
}
|
|
25
api/.vscode/api-snippets.code-snippets
vendored
25
api/.vscode/api-snippets.code-snippets
vendored
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"API Router": {
|
|
||||||
"scope": "javascript,typescript",
|
|
||||||
"prefix": "router",
|
|
||||||
"body": [
|
|
||||||
"import { Router, Response, Request } from \"express\";",
|
|
||||||
"import { route } from \"@fosscord/api\";",
|
|
||||||
"",
|
|
||||||
"const router = Router();",
|
|
||||||
"",
|
|
||||||
"router.get(\"/\", route({}), (req: Request, res: Response) => {",
|
|
||||||
"\tres.json({});",
|
|
||||||
"});",
|
|
||||||
"",
|
|
||||||
"export default router;"
|
|
||||||
],
|
|
||||||
"description": "A basic API router setup for a blank route."
|
|
||||||
},
|
|
||||||
"Route": {
|
|
||||||
"scope": "typescript",
|
|
||||||
"prefix": "route",
|
|
||||||
"body": ["router.get(\"$1\", route({}), (req: Request, res: Response) => {", "\t$2", "});"],
|
|
||||||
"description": "An API endpoint"
|
|
||||||
}
|
|
||||||
}
|
|
28
api/.vscode/launch.json
vendored
28
api/.vscode/launch.json
vendored
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"sourceMaps": true,
|
|
||||||
"type": "node",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Server",
|
|
||||||
"program": "${workspaceFolder}/dist/start.js",
|
|
||||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
|
||||||
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
|
|
||||||
"envFile": "${workspaceFolder}/.env"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Debug current file",
|
|
||||||
"program": "${file}",
|
|
||||||
"request": "launch",
|
|
||||||
"skipFiles": ["<node_internals>/**"],
|
|
||||||
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
|
|
||||||
"preLaunchTask": "tsc: build - tsconfig.json",
|
|
||||||
"type": "node",
|
|
||||||
"resolveSourceMapLocations": ["${workspaceFolder}/**", "!**/node_modules/**"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
FROM node:lts-alpine
|
|
||||||
# needed for native packages (bcrypt, canvas)
|
|
||||||
RUN apk add --no-cache make gcc g++ python cairo-dev jpeg-dev pango-dev giflib-dev
|
|
||||||
WORKDIR /usr/src/fosscord-server
|
|
||||||
COPY package.json .
|
|
||||||
COPY package-lock.json .
|
|
||||||
RUN npm rebuild bcrypt --build-from-source && npm install canvas --build-from-source
|
|
||||||
RUN npm install
|
|
||||||
COPY . .
|
|
||||||
EXPOSE 3001
|
|
||||||
RUN npm run build-docker
|
|
||||||
CMD ["node", "dist/start.js"]
|
|
@ -1,67 +0,0 @@
|
|||||||
<p align="center">
|
|
||||||
<img width="100" src="https://raw.githubusercontent.com/fosscord/fosscord/master/assets/logo_big_transparent.png" />
|
|
||||||
</p>
|
|
||||||
<h1 align="center">Fosscord HTTP API Server</h1>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="https://discord.gg/ZrnGQP6p3d">
|
|
||||||
<img src="https://img.shields.io/discord/806142446094385153?color=7489d5&logo=discord&logoColor=ffffff" />
|
|
||||||
</a>
|
|
||||||
<img src="https://img.shields.io/static/v1?label=Status&message=Development&color=blue">
|
|
||||||
<a title="Crowdin" target="_blank" href="https://translate.fosscord.com/"><img src="https://badges.crowdin.net/fosscord/localized.svg"></a>
|
|
||||||
<a href="https://opencollective.com/fosscord">
|
|
||||||
<img src="https://opencollective.com/fosscord/tiers/badge.svg">
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## [About](https://github.com/fosscord/fosscord-server/wiki)
|
|
||||||
|
|
||||||
This repository contains the Fosscord HTTP API Server
|
|
||||||
|
|
||||||
## Bug Tracker
|
|
||||||
|
|
||||||
[Project Board](https://fosscord.notion.site/2c7fe9e73f9842d3bab3a4912dedd091)
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
We use [express](https://expressjs.com/) for the HTTP Server and
|
|
||||||
[lambert-server](https://www.npmjs.com/package/lambert-server) for route handling and body validation (customized).
|
|
||||||
|
|
||||||
## Contribution
|
|
||||||
|
|
||||||
You should be familiar with:
|
|
||||||
|
|
||||||
- [Git](https://git-scm.com/)
|
|
||||||
- [NodeJS](https://nodejs.org/)
|
|
||||||
- [TypeScript](https://www.typescriptlang.org/)
|
|
||||||
- [MongoDB/mongoose](http://mongoosejs.com/)
|
|
||||||
|
|
||||||
and the other technologies we use
|
|
||||||
|
|
||||||
### Getting Started
|
|
||||||
|
|
||||||
Clone the Repository:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/fosscord/fosscord-server
|
|
||||||
cd fosscord-server
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Install (dev)dependencies:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
npm install --only=dev
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Starting:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Debugging:
|
|
||||||
|
|
||||||
**Vscode:**
|
|
||||||
The Launch file configuration is in `./vscode/launch.json`,
|
|
||||||
so you can just debug the server by pressing `F5` or the `> Launch Server` button
|
|
@ -1,13 +0,0 @@
|
|||||||
const redirectIfOnLogin = () => {
|
|
||||||
const path = window.location.pathname;
|
|
||||||
if (path == "/login" || path == "/register") {
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const observer = new MutationObserver((mutations) => {
|
|
||||||
redirectIfOnLogin();
|
|
||||||
});
|
|
||||||
observer.observe(document, { subtree: true, childList: true })
|
|
||||||
|
|
||||||
redirectIfOnLogin();
|
|
@ -1,6 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
presets: [
|
|
||||||
["@babel/preset-env", { targets: { node: "current" } }],
|
|
||||||
["@babel/preset-typescript", { allowDeclareFields: true }]
|
|
||||||
]
|
|
||||||
};
|
|
@ -1,66 +0,0 @@
|
|||||||
const { traverseDirectory } = require("lambert-server");
|
|
||||||
const path = require("path");
|
|
||||||
const express = require("express");
|
|
||||||
const RouteUtility = require("../dist/util/route");
|
|
||||||
const Router = express.Router;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some documentation.
|
|
||||||
*
|
|
||||||
* @type {Map<string, RouteUtility.RouteOptions>}
|
|
||||||
*/
|
|
||||||
const routes = new Map();
|
|
||||||
let currentPath = "";
|
|
||||||
let currentFile = "";
|
|
||||||
const methods = ["get", "post", "put", "delete", "patch"];
|
|
||||||
|
|
||||||
function registerPath(file, method, prefix, path, ...args) {
|
|
||||||
const urlPath = prefix + path;
|
|
||||||
const sourceFile = file.replace("/dist/", "/src/").replace(".js", ".ts");
|
|
||||||
const opts = args.find((x) => typeof x === "object");
|
|
||||||
if (opts) {
|
|
||||||
routes.set(urlPath + "|" + method, opts); // @ts-ignore
|
|
||||||
opts.file = sourceFile;
|
|
||||||
// console.log(method, urlPath, opts);
|
|
||||||
} else {
|
|
||||||
console.log(`${sourceFile}\nrouter.${method}("${path}") is missing the "route()" description middleware\n`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function routeOptions(opts) {
|
|
||||||
return opts;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
RouteUtility.route = routeOptions;
|
|
||||||
|
|
||||||
express.Router = (opts) => {
|
|
||||||
const path = currentPath;
|
|
||||||
const file = currentFile;
|
|
||||||
const router = Router(opts);
|
|
||||||
|
|
||||||
for (const method of methods) {
|
|
||||||
router[method] = registerPath.bind(null, file, method, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return router;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function getRouteDescriptions() {
|
|
||||||
const root = path.join(__dirname, "..", "dist", "routes", "/");
|
|
||||||
traverseDirectory({ dirname: root, recursive: true }, (file) => {
|
|
||||||
currentFile = file;
|
|
||||||
let path = file.replace(root.slice(0, -1), "");
|
|
||||||
path = path.split(".").slice(0, -1).join("."); // trancate .js/.ts file extension of path
|
|
||||||
path = path.replaceAll("#", ":").replaceAll("\\", "/"); // replace # with : for path parameters and windows paths with slashes
|
|
||||||
if (path.endsWith("/index")) path = path.slice(0, "/index".length * -1); // delete index from path
|
|
||||||
currentPath = path;
|
|
||||||
|
|
||||||
try {
|
|
||||||
require(file);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("error loading file " + file, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return routes;
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
const { Config, initDatabase } = require("@fosscord/util");
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const { FosscordServer } = require("../dist/Server");
|
|
||||||
const Server = new FosscordServer({ port: 3001 });
|
|
||||||
global.server = Server;
|
|
||||||
module.exports = async () => {
|
|
||||||
try {
|
|
||||||
fs.unlinkSync(path.join(process.cwd(), "database.db"));
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
await initDatabase();
|
|
||||||
await Config.init();
|
|
||||||
Config.get().limits.rate.disabled = true;
|
|
||||||
return await Server.start();
|
|
||||||
};
|
|
||||||
|
|
||||||
// afterAll(async () => {
|
|
||||||
// return await Server.stop();
|
|
||||||
// });
|
|
@ -1,2 +0,0 @@
|
|||||||
jest.spyOn(global.console, "log").mockImplementation(() => jest.fn());
|
|
||||||
jest.spyOn(global.console, "info").mockImplementation(() => jest.fn());
|
|
25947
api/package-lock.json
generated
25947
api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
106
api/package.json
106
api/package.json
@ -1,106 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@fosscord/api",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "This repository contains the HTTP API Server",
|
|
||||||
"main": "dist/index.js",
|
|
||||||
"types": "src/index.ts",
|
|
||||||
"scripts": {
|
|
||||||
"test:only": "npx jest --coverage --verbose --forceExit ./tests",
|
|
||||||
"test:routes": "npx jest --coverage --verbose --forceExit ./routes.test.ts",
|
|
||||||
"test": "npm run build && npm run test:only",
|
|
||||||
"test:watch": "npx jest --watch",
|
|
||||||
"start": "npm run build && node dist/start",
|
|
||||||
"build": "npx tsc -p .",
|
|
||||||
"dev": "npx tsnd --respawn src/start.ts",
|
|
||||||
"patch": "npx ts-patch install -s && npx patch-package",
|
|
||||||
"postinstall": "npm run patch",
|
|
||||||
"generate:docs": "node scripts/generate_openapi",
|
|
||||||
"generate:schema": "node scripts/generate_schema"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/fosscord/fosscord-server.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"discord",
|
|
||||||
"fosscord",
|
|
||||||
"fosscord-server",
|
|
||||||
"fosscord-api",
|
|
||||||
"discord open source",
|
|
||||||
"discord-open-source"
|
|
||||||
],
|
|
||||||
"author": "Fosscord",
|
|
||||||
"license": "AGPL-3.0-only",
|
|
||||||
"bugs": {
|
|
||||||
"url": "https://github.com/fosscord/fosscord-server/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://fosscord.com",
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.15.5",
|
|
||||||
"@babel/preset-env": "^7.15.8",
|
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
|
||||||
"@types/amqplib": "^0.8.1",
|
|
||||||
"@types/bcrypt": "^5.0.0",
|
|
||||||
"@types/express": "^4.17.9",
|
|
||||||
"@types/i18next-node-fs-backend": "^2.1.0",
|
|
||||||
"@types/jest": "^27.0.1",
|
|
||||||
"@types/jest-expect-message": "^1.0.3",
|
|
||||||
"@types/jsonwebtoken": "^8.5.0",
|
|
||||||
"@types/morgan": "^1.9.3",
|
|
||||||
"@types/multer": "^1.4.5",
|
|
||||||
"@types/node": "^14.17.9",
|
|
||||||
"@types/node-fetch": "^2.5.5",
|
|
||||||
"@types/supertest": "^2.0.11",
|
|
||||||
"@zerollup/ts-transform-paths": "^1.7.18",
|
|
||||||
"jest": "^27.2.5",
|
|
||||||
"jest-expect-message": "^1.0.2",
|
|
||||||
"jest-runtime": "^27.2.1",
|
|
||||||
"ts-node": "^9.1.1",
|
|
||||||
"ts-node-dev": "^1.1.6",
|
|
||||||
"ts-patch": "^1.4.4",
|
|
||||||
"typescript": "^4.4.2",
|
|
||||||
"typescript-json-schema": "0.50.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@babel/preset-env": "^7.15.8",
|
|
||||||
"@babel/preset-typescript": "^7.15.0",
|
|
||||||
"@fosscord/util": "file:../util",
|
|
||||||
"@sentry/node": "^6.16.1",
|
|
||||||
"@sentry/tracing": "^6.16.1",
|
|
||||||
"ajv": "8.6.2",
|
|
||||||
"ajv-formats": "^2.1.1",
|
|
||||||
"amqplib": "^0.8.0",
|
|
||||||
"assert": "^1.5.0",
|
|
||||||
"bcrypt": "^5.0.1",
|
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"cheerio": "^1.0.0-rc.10",
|
|
||||||
"dotenv": "^8.2.0",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"form-data": "^3.0.0",
|
|
||||||
"i18next": "^19.9.2",
|
|
||||||
"i18next-http-middleware": "^3.1.3",
|
|
||||||
"i18next-node-fs-backend": "^2.1.3",
|
|
||||||
"image-size": "^1.0.0",
|
|
||||||
"jsonwebtoken": "^8.5.1",
|
|
||||||
"lambert-server": "^1.2.12",
|
|
||||||
"missing-native-js-functions": "^1.2.18",
|
|
||||||
"morgan": "^1.10.0",
|
|
||||||
"multer": "^1.4.2",
|
|
||||||
"node-fetch": "^2.6.2",
|
|
||||||
"patch-package": "^6.4.7",
|
|
||||||
"picocolors": "^1.0.0",
|
|
||||||
"proxy-agent": "^5.0.0",
|
|
||||||
"supertest": "^6.1.6",
|
|
||||||
"typeorm": "^0.2.37"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"setupFiles": [
|
|
||||||
"<rootDir>/jest/setup.js"
|
|
||||||
],
|
|
||||||
"setupFilesAfterEnv": [
|
|
||||||
"jest-expect-message"
|
|
||||||
],
|
|
||||||
"globalSetup": "<rootDir>/jest/globalSetup.js",
|
|
||||||
"verbose": true
|
|
||||||
}
|
|
||||||
}
|
|
8
api/src/global.d.ts
vendored
8
api/src/global.d.ts
vendored
@ -1,8 +0,0 @@
|
|||||||
declare global {
|
|
||||||
namespace Express {
|
|
||||||
interface Request {
|
|
||||||
user_id: any;
|
|
||||||
token: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,155 +0,0 @@
|
|||||||
// TODO: check every route based on route() parameters: https://github.com/fosscord/fosscord-server/issues/308
|
|
||||||
// TODO: check every route with different database engine
|
|
||||||
|
|
||||||
import getRouteDescriptions from "../jest/getRouteDescriptions";
|
|
||||||
import { join } from "path";
|
|
||||||
import fs from "fs";
|
|
||||||
import Ajv from "ajv";
|
|
||||||
import addFormats from "ajv-formats";
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
import { Event, User, events, Guild, Channel } from "@fosscord/util";
|
|
||||||
|
|
||||||
const SchemaPath = join(__dirname, "..", "assets", "schemas.json");
|
|
||||||
const schemas = JSON.parse(fs.readFileSync(SchemaPath, { encoding: "utf8" }));
|
|
||||||
export const ajv = new Ajv({
|
|
||||||
allErrors: true,
|
|
||||||
parseDate: true,
|
|
||||||
allowDate: true,
|
|
||||||
schemas,
|
|
||||||
messages: true,
|
|
||||||
strict: true,
|
|
||||||
strictRequired: true,
|
|
||||||
coerceTypes: true
|
|
||||||
});
|
|
||||||
addFormats(ajv);
|
|
||||||
|
|
||||||
var token: string;
|
|
||||||
var user: User;
|
|
||||||
var guild: Guild;
|
|
||||||
var channel: Channel;
|
|
||||||
|
|
||||||
const request = async (path: string, opts: any = {}): Promise<any> => {
|
|
||||||
const response = await fetch(`http://localhost:3001/api${path}`, {
|
|
||||||
...opts,
|
|
||||||
method: opts.method || opts.body ? "POST" : "GET",
|
|
||||||
body: opts.body && JSON.stringify(opts.body),
|
|
||||||
headers: {
|
|
||||||
authorization: token,
|
|
||||||
...(opts.body ? { "content-type": "application/json" } : {}),
|
|
||||||
...(opts.header || {})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (response.status === 204) return;
|
|
||||||
|
|
||||||
var data = await response.text();
|
|
||||||
try {
|
|
||||||
data = JSON.parse(data);
|
|
||||||
if (response.status >= 400) throw data;
|
|
||||||
return data;
|
|
||||||
} catch (error) {
|
|
||||||
throw data;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeAll(async (done) => {
|
|
||||||
try {
|
|
||||||
const response = await request("/auth/register", {
|
|
||||||
body: {
|
|
||||||
fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
|
|
||||||
username: "tester",
|
|
||||||
invite: null,
|
|
||||||
consent: true,
|
|
||||||
date_of_birth: "2000-01-01",
|
|
||||||
gift_code_sku_id: null,
|
|
||||||
captcha_key: null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
token = response.token;
|
|
||||||
user = await request(`/users/@me`);
|
|
||||||
const { id: guild_id } = await request("/guilds", { body: { name: "test server" } });
|
|
||||||
guild = await request(`/guilds/${guild_id}`);
|
|
||||||
channel = (await request(`/guilds/${guild_id}/channels`))[0];
|
|
||||||
|
|
||||||
done();
|
|
||||||
} catch (error) {
|
|
||||||
done(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const emit = events.emit;
|
|
||||||
events.emit = (event: string | symbol, ...args: any[]) => {
|
|
||||||
events.emit("event", args[0]);
|
|
||||||
return emit(event, ...args);
|
|
||||||
};
|
|
||||||
|
|
||||||
describe("Automatic unit tests with route description middleware", () => {
|
|
||||||
const routes = getRouteDescriptions();
|
|
||||||
|
|
||||||
routes.forEach((route, pathAndMethod) => {
|
|
||||||
const [path, method] = pathAndMethod.split("|");
|
|
||||||
|
|
||||||
test(`${method.toUpperCase()} ${path}`, async (done) => {
|
|
||||||
if (!route.test) {
|
|
||||||
console.log(`${(route as any).file}\nrouter.${method} is missing the test property`);
|
|
||||||
return done();
|
|
||||||
}
|
|
||||||
const urlPath =
|
|
||||||
path.replace(":id", user.id).replace(":guild_id", guild.id).replace(":channel_id", channel.id) || route.test?.path;
|
|
||||||
var validate: any;
|
|
||||||
if (route.test.body) {
|
|
||||||
validate = ajv.getSchema(route.test.body);
|
|
||||||
if (!validate) return done(new Error(`Response schema ${route.test.body} not found`));
|
|
||||||
}
|
|
||||||
|
|
||||||
var body = "";
|
|
||||||
let eventEmitted = Promise.resolve();
|
|
||||||
|
|
||||||
if (route.test.event) {
|
|
||||||
if (!Array.isArray(route.test.event)) route.test.event = [route.test.event];
|
|
||||||
|
|
||||||
eventEmitted = new Promise((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => reject, 1000);
|
|
||||||
const received = [];
|
|
||||||
|
|
||||||
events.on("event", (event: Event) => {
|
|
||||||
if (!route.test.event.includes(event.event)) return;
|
|
||||||
|
|
||||||
received.push(event.event);
|
|
||||||
if (received.length === route.test.event.length) resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(`http://localhost:3001/api${urlPath}`, {
|
|
||||||
method: method.toUpperCase(),
|
|
||||||
body: JSON.stringify(route.test.body),
|
|
||||||
headers: { ...route.test.headers, authorization: token }
|
|
||||||
});
|
|
||||||
|
|
||||||
body = await response.text();
|
|
||||||
|
|
||||||
expect(response.status, body).toBe(route.test.response.status || 200);
|
|
||||||
|
|
||||||
// TODO: check headers
|
|
||||||
// TODO: expect event
|
|
||||||
|
|
||||||
if (validate) {
|
|
||||||
body = JSON.parse(body);
|
|
||||||
const valid = validate(body);
|
|
||||||
if (!valid) return done(validate.errors);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return done(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await eventEmitted;
|
|
||||||
} catch (error) {
|
|
||||||
return done(new Error(`Event ${route.test.event} was not emitted`));
|
|
||||||
}
|
|
||||||
|
|
||||||
return done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,33 +0,0 @@
|
|||||||
const supertest = require("supertest");
|
|
||||||
const request = supertest("http://localhost:3001");
|
|
||||||
|
|
||||||
describe("/api/auth/login", () => {
|
|
||||||
describe("POST", () => {
|
|
||||||
test("without body", async () => {
|
|
||||||
const response = await request.post("/api/auth/login").send({});
|
|
||||||
expect(response.statusCode).toBe(400);
|
|
||||||
});
|
|
||||||
test("with body", async () => {
|
|
||||||
const user = {
|
|
||||||
login: "fortnitefortnite@gmail.com",
|
|
||||||
password: "verysecurepassword"
|
|
||||||
};
|
|
||||||
|
|
||||||
await request.post("/api/auth/register").send({
|
|
||||||
fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
|
|
||||||
email: user.login,
|
|
||||||
username: user.login.split("@")[0],
|
|
||||||
password: user.password,
|
|
||||||
invite: null,
|
|
||||||
consent: true,
|
|
||||||
date_of_birth: "2000-04-04",
|
|
||||||
gift_code_sku_id: null,
|
|
||||||
captcha_key: null
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await request.post("/api/auth/login").send(user);
|
|
||||||
|
|
||||||
expect(response.statusCode).toBe(200);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,27 +0,0 @@
|
|||||||
const supertest = require("supertest");
|
|
||||||
const request = supertest("http://localhost:3001");
|
|
||||||
|
|
||||||
describe("/api/auth/register", () => {
|
|
||||||
describe("POST", () => {
|
|
||||||
test("without body", async () => {
|
|
||||||
const response = await request.post("/api/auth/register").send({});
|
|
||||||
|
|
||||||
expect(response.statusCode).toBe(400);
|
|
||||||
});
|
|
||||||
test("with body", async () => {
|
|
||||||
const response = await request.post("/api/auth/register").send({
|
|
||||||
fingerprint: "805826570869932034.wR8vi8lGlFBJerErO9LG5NViJFw",
|
|
||||||
email: "qo8etzvaf@gmail.com",
|
|
||||||
username: "qp39gr98",
|
|
||||||
password: "wtp9gep9gw",
|
|
||||||
invite: null,
|
|
||||||
consent: true,
|
|
||||||
date_of_birth: "2000-04-04",
|
|
||||||
gift_code_sku_id: null,
|
|
||||||
captcha_key: null
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(response.statusCode).toBe(200);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
const supertest = require("supertest");
|
|
||||||
const request = supertest("http://localhost:3001");
|
|
||||||
|
|
||||||
describe("/ping", () => {
|
|
||||||
describe("GET", () => {
|
|
||||||
test("should return 200 and pong", async () => {
|
|
||||||
let response = await request.get("/api/ping");
|
|
||||||
expect(response.text).toBe("pong");
|
|
||||||
expect(response.statusCode).toBe(200);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,76 +0,0 @@
|
|||||||
{
|
|
||||||
"exclude": ["node_modules"],
|
|
||||||
"include": ["src/**/*.ts"],
|
|
||||||
"compilerOptions": {
|
|
||||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
|
||||||
|
|
||||||
/* Basic Options */
|
|
||||||
"incremental": true /* Enable incremental compilation */,
|
|
||||||
"target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
|
|
||||||
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
|
|
||||||
"lib": ["ES2021"] /* Specify library files to be included in the compilation. */,
|
|
||||||
"allowJs": true /* Allow javascript files to be compiled. */,
|
|
||||||
"checkJs": true /* Report errors in .js files. */,
|
|
||||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
|
||||||
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
|
||||||
"declarationMap": false /* Generates a sourcemap for each corresponding '.d.ts' file. */,
|
|
||||||
"sourceMap": true /* Generates corresponding '.map' file. */,
|
|
||||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
|
||||||
"outDir": "./dist/" /* Redirect output structure to the directory. */,
|
|
||||||
"rootDir": "./src/" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,
|
|
||||||
// "composite": true, /* Enable project compilation */
|
|
||||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
|
||||||
// "removeComments": true, /* Do not emit comments to output. */
|
|
||||||
// "noEmit": true, /* Do not emit outputs. */
|
|
||||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
|
||||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
|
||||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
|
||||||
|
|
||||||
/* Strict Type-Checking Options */
|
|
||||||
"strict": true /* Enable all strict type-checking options. */,
|
|
||||||
"noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
|
|
||||||
"strictNullChecks": true /* Enable strict null checks. */,
|
|
||||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
|
||||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
|
||||||
"strictPropertyInitialization": false /* Enable strict checking of property initialization in classes. */,
|
|
||||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
|
||||||
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
|
|
||||||
|
|
||||||
/* Additional Checks */
|
|
||||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
|
||||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
|
||||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
||||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
||||||
|
|
||||||
/* Module Resolution Options */
|
|
||||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
|
||||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
|
||||||
"types": ["node"] /* Type declaration files to be included in compilation. */,
|
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
|
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
|
||||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
|
||||||
|
|
||||||
/* Source Map Options */
|
|
||||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
|
||||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
|
||||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
|
||||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
|
||||||
|
|
||||||
/* Experimental Options */
|
|
||||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
|
||||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
|
||||||
|
|
||||||
/* Advanced Options */
|
|
||||||
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
|
||||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@fosscord/api": ["src/index"]
|
|
||||||
"@fosscord/util": ["../util/src/index"]
|
|
||||||
},
|
|
||||||
"plugins": [{ "transform": "@zerollup/ts-transform-paths" }],
|
|
||||||
"experimentalDecorators": true
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 312 KiB |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user