Inital commit
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Simon Giesel 2020-04-29 11:33:39 +02:00
commit 470ed4a47d
29 changed files with 13389 additions and 0 deletions

47
.drone.yml Normal file
View file

@ -0,0 +1,47 @@
kind: pipeline
name: default
steps:
- name: install
image: node:14.0
commands:
- npm --prefix ./server install ./server
- name: test
image: node:14.0
commands:
- npm --prefix ./server run test
- name: lint
image: node:14.0
commands:
- npm --prefix ./server run lint
- name: build
image: node:14.0
commands:
- npm --prefix ./server run build
when:
event:
- push
- tag
- deployment
- name: deploy
image: plugins/docker
settings:
registry: registry.cliffbreak.de
repo: registry.cliffbreak.de/tsviewer
username:
from_secret: docker_username
password:
from_secret: docker_password
when:
event:
- push
- tag
- deployment
trigger:
branch:
- master

112
.gitignore vendored Normal file
View file

@ -0,0 +1,112 @@
# ---> Node
# 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
# 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
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
## Custom direcotries
dist/
webapp/assets/

9
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,9 @@
{
"recommendations": [
"dbaeumer.vscode-eslint",
"sibiraj-s.vscode-scss-formatter",
"mikestead.dotenv",
"streetsidesoftware.code-spell-checker",
"streetsidesoftware.code-spell-checker-german",
]
}

23
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,23 @@
{
"editor.formatOnSave": true,
"html.format.indentHandlebars": true,
"eslint.workingDirectories": [
"./server",
],
"eslint.format.enable": true,
"cSpell.language": "de,en,de-DE,en-US",
"cSpell.words": [
"Giesel",
"Gitea",
"Roboto",
"camelcase",
"channellist",
"clid",
"cliffbreak",
"fastify",
"ijmap",
"nestjs",
"tsviewer",
"uglifycss"
],
}

78
COMMIT_CONVENTION.md Normal file
View file

@ -0,0 +1,78 @@
### Commit Message Format
Each commit message consists of a **header**, a **body** and a **footer**. The header has a special
format that includes a **type**, a **scope** and a **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on Gitea as well as in various git tools.
The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-using-keywords/) if any.
Samples:
```
docs(readme): update change log to beta.5
```
```
style(server): reorder imports
```
```
fix(webapp): ui animations should now play on the right time
Closes #123
```
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, npm)
* **ci**: Changes to our CI configuration files and scripts (example scopes: drone)
* **docs**: Documentation only changes
* **feat**: A new feature
* **fix**: A bug fix
* **perf**: A code change that improves performance
* **refactor**: A code change that neither fixes a bug nor adds a feature
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
* **test**: Adding missing tests or correcting existing tests
* **bump**: Bump a version to X
### Scope
The following is the list of supported scopes (more to come):
* **core**: used for changes made in server and webapp
* **server** used for changes made in the server
* **webapp** used for changes made in the webapp
* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`)
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
### More Infos
To generate a changelog **[conventional-changelog](https://github.com/conventional-changelog/conventional-changelog)** is used.

9
Dockerfile Normal file
View file

@ -0,0 +1,9 @@
FROM node:14.0
ENV NODE_ENV dev
WORKDIR /usr/src/app
COPY server/package*.json ./server/
COPY server/.env.example ./server/.env
RUN npm --prefix ./server install --production ./server --silent
COPY . .
EXPOSE 3000
CMD npm --prefix ./server start

101
README.md Normal file
View file

@ -0,0 +1,101 @@
# Cliffbreak TS-Viewer 🔎
This is the main Repository containing all required resources to run the server and a corresponding website.
`/server` contains the complete backend. Offering a REST API for all actions.
`/webapp` contains the Web App, communicating with the REST API from `/server`.
## Getting Started
The following instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
After setting up you local environment, you can access the following services with your web browser:
* Web frontend via [http://localhost:8080/](http://localhost:8080/)
* API documentation via [http://localhost:8080/api-docs/](http://localhost:8080/api-docs/)
### Prerequisites
`NodeJS (including NPM)` is required to run this project.
You'll also need `git` if you want to contribute to the project.
### Installing
First clone this repository to your local machine by using
```
git clone https://git.cliffbreak.de/Cliffbreak/CliffbreakTS-Viewer.git
```
Change to the cloned repository and inside change your active directory to `server`
```
cd CliffbreakTS-Viewer && cd server
```
To install all required packages run
```
npm install
```
Copy the .env.example and paste it as .env
```
cp .env.example .env
```
To test the application run
```
npm test
```
To start the server in development mode run the following npm script
```
npm run dev
```
## Configure Visual Studio Code
If you haven't a instance of Visual Studio Code up and running download the latest version [here](https://code.visualstudio.com/download).
Install the recommended extensions by opening the Extensions-Tab (Ctrl+Shift+X).
Enter `@recommended` and install all extensions.
After that restart Visual Studio Code to apply all changes.
## Contributing
First create an issue and assign it to yourself. Or assign an existing issue.
Make sure all issue details (description, labels, milestones) are correct.
Check out in a new branch. Notice our convention: use either feature or fix followed by a slash (`/`) and then a **short** description using camel case. (`fix/addMissingImports` or `feature/addBasicAuth`).
After that you may create a Pull Request to merge your changes into master (If it's work in progress add `WIP:` to the title!).
Also refer to our **[COMMIT_CONVENTION](COMMIT_CONVENTION.md)**
## Deployment
In this section you can read details on the deployment cycle.
### Changelog
After bumping the version in the `package.json` please run:
```
npm install
```
to update all packages and bump the application version.
After that generate a changelog via the `changelog` gulp script.
```
npm run changelog
```
Then commit and tag your changes using: (use this format for versioning: `v[major][minor][patch]` i.e. v1.2.3)
```
git commit -m 'bump: to {version}
git tag {version}
git push origin
git push origin --tags
```
## Built With
* [Node.js](https://nodejs.org/) - The JavaScript runtime used as the project's base
* [NestJS](https://docs.nestjs.com/) - The framework used to create the REST API
* [HandlebarsJS](https://handlebarsjs.com/) - Dynamic HTML renderer using templates
## Authors
* **Simon Giesel** - *Initial work* - [Simon Giesel](https://git.cliffbreak.de/SimGie)

23
docker-compose.yml Normal file
View file

@ -0,0 +1,23 @@
version: '2.1'
networks:
proxy:
external:
name: proxy
services:
tsviewer:
container_name: tsviewer
restart: always
image: registry.cliffbreak.de/tsviewer
environment:
NODE_ENV: production
PRODUCTION: true
TEAMSPEAK_HOST: example.com
TEAMSPEAK_QUERY_NAME: Query-User
TEAMSPEAK_QUERY_PASS: secret
PORT: 3000
expose:
- 3000
networks:
- proxy

6
server/ .eslintignore Normal file
View 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)
dist
# don't lint nyc coverage output
coverage

7
server/.env.example Normal file
View file

@ -0,0 +1,7 @@
PRODUCTION=false
TEAMSPEAK_HOST=example.com
TEAMSPEAK_QUERY_NAME=Query-User
TEAMSPEAK_QUERY_PASS=secret
PORT=8080

89
server/.eslintrc.js Normal file
View file

@ -0,0 +1,89 @@
module.exports = {
root: true,
extends: [
'eslint:recommended',
],
parserOptions: {
'ecmaVersion': 2017,
},
env: {
'node': true,
'es6': true,
},
rules: {
'camelcase': ['error', {
'properties': 'always',
'ignoreDestructuring': false,
'ignoreImports': false,
}],
// 'capitalized-comments': ['error', 'always'],
'comma-dangle': ['error', 'always-multiline'],
'comma-spacing': ['error', { 'before': false, 'after': true }],
'curly': ['error', 'all'],
'eol-last': ['error', 'never'],
'indent': ['error', 4],
'key-spacing': ['error', {
'beforeColon': false,
'afterColon': true,
'mode': 'strict',
}],
'keyword-spacing': ['error', {
'after': true,
'overrides': {
'if': { 'after': false },
'for': { 'after': false },
'while': { 'after': false },
},
}],
'max-classes-per-file': ['error', 1],
'max-len': ['error', 150],
'no-console': ['warn'],
'no-empty': ['error', { 'allowEmptyCatch': false }],
'no-multi-spaces': ['error', { 'ignoreEOLComments': false }],
'no-trailing-spaces': ['error', { 'ignoreComments': false }],
'no-warning-comments': ['warn', { 'location': 'start' }],
'object-curly-spacing': ['error', 'always'],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],
'sort-imports': ['error', {
'ignoreCase': false,
'ignoreDeclarationSort': false,
'ignoreMemberSort': false,
'memberSyntaxSortOrder': ['none', 'all', 'multiple', 'single']
}],
'sort-vars': ['error', { 'ignoreCase': true }],
'space-before-blocks': ['error', 'always'],
'space-before-function-paren': ['error', {
'anonymous': 'always',
'named': 'never',
'asyncArrow': 'always'
}],
'space-in-parens': ['error', 'never'],
'spaced-comment': ['error', 'always'],
},
overrides: [
{
files: ['*.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: 'tsconfig.json',
},
plugins: [
'@typescript-eslint',
],
extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
// '@typescript-eslint/array-type': ['error', {
// 'default': 'array',
// 'readonly': 'array-simple',
// }],
'@typescript-eslint/interface-name-prefix': ['error', 'always'],
'@typescript-eslint/no-empty-interface': ['error', { 'allowSingleExtends': false }],
'@typescript-eslint/type-annotation-spacing': ['error', { 'before': false, 'after': true }],
}
}
],
};

144
server/gulpfile.js Normal file
View file

@ -0,0 +1,144 @@
const { dest, parallel, series, src, watch } = require('gulp'),
changed = require('gulp-changed'),
conventionalChangelog = require('gulp-conventional-changelog'),
dateFormat = require('dateformat'),
del = require('del'),
path = require('path'),
rename = require('gulp-rename'),
sass = require('gulp-sass'),
ts = require('gulp-typescript'),
uglifycss = require('gulp-uglifycss'),
webpack = require('webpack-stream');
require('dotenv').config();
function clean() {
return del(
[
'./dist/',
'./../webapp/assets/css/',
'./../webapp/assets/fonts/',
'./../webapp/assets/js/',
], { force: true }); // Force option needed to delete files outside of project dir
}
function compileJavaScript() {
return src('./../webapp/src/js/app.js')
.pipe(webpack({
entry: {
app: './../webapp/src/js/app.js',
},
output: {
filename: '[name].js',
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
mode: process.env.PRODUCTION ? 'production' : 'development',
resolve: {
modules: [
path.resolve('./../server/node_modules'),
],
extensions: ['.js', '.json'],
// alias: {
// handlebars: 'handlebars/dist/handlebars.min.js',
// },
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
query: {
presets: [
[
'@babel/preset-env',
{
targets: {
chrome: 78,
},
},
],
],
},
},
],
},
}).on('error', function () { this.emit('end'); }))
.pipe(dest('./../webapp/assets/js/'));
}
function compileScss() {
return src('./../webapp/src/scss/*.scss')
.pipe(sass({ outputStyle: 'compressed', includePaths: ['./../server/node_modules/'] })).on('error', sass.logError)
.pipe(dest('./../webapp/assets/css/'));
}
function compileTypeScript() {
const tsProject = ts.createProject('tsconfig.json');
// do not compile tests in production
tsProject.config.exclude = !tsProject.config.exclude ? ['test'] : tsProject.config.exclude.push('test');
return tsProject.src()
.pipe(tsProject())
.js.pipe(dest('./dist/'));
}
function installMaterialIcons() {
src(
'./node_modules/material-design-icons/iconfont/*.css')
.pipe(uglifycss())
.pipe(changed('./../webapp/assets/fonts/material-icons/'))
.pipe(dest('./../webapp/assets/fonts/material-icons/'));
return src(
'./node_modules/material-design-icons/iconfont/*',
{ ignore: ['**/README.md', '**/codepoints', '**/*.ijmap'] })
.pipe(changed('./../webapp/assets/fonts/material-icons/'))
.pipe(dest('./../webapp/assets/fonts/material-icons/'));
}
function installRoboto() {
src('./node_modules/typeface-roboto/files/*')
.pipe(changed('./../webapp/assets/fonts/roboto/files/'))
.pipe(dest('./../webapp/assets/fonts/roboto/files/'));
return src('./node_modules/typeface-roboto/index.css')
.pipe(rename('roboto.css'))
.pipe(uglifycss())
.pipe(changed('./../webapp/assets/fonts/roboto/'))
.pipe(dest('./../webapp/assets/fonts/roboto/'));
}
function watchCompile() {
watch('./../webapp/src/scss/*.scss', { ignoreInitial: false }, compileScss);
watch('./../webapp/src/js/*.js', { ignoreInitial: false }, compileJavaScript);
}
function changelog() {
return src('../CHANGELOG.md')
.pipe(conventionalChangelog({
// conventional-changelog options go here
preset: 'angular',
// releaseCount: 0, // Uncomment to regenerate whole changelog
}, {
// context goes here
commit: 'commit',
date: dateFormat(new Date(), 'dd.mm.yyyy', true),
}, {
// git-raw-commits options go here
}, {
// conventional-commits-parser options go here
}, {
// conventional-changelog-writer options go here
}))
.pipe(dest('../'));
}
exports.clean = clean;
exports.compileFonts = parallel(installMaterialIcons, installRoboto);
exports.compile = parallel(compileScss, compileJavaScript, compileTypeScript, exports.compileFonts);
exports.watchCompile = series(clean, exports.compileFonts, watchCompile);
exports.build = series(clean, exports.compile);
exports.changelog = changelog;
exports.default = exports.build;

12425
server/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

61
server/package.json Normal file
View file

@ -0,0 +1,61 @@
{
"name": "ts-viewer",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"build": "gulp",
"clean": "gulp clean",
"dev": "concurrently --kill-others \"gulp watchCompile\" \"npm run dev:node\"",
"dev:node": "node -r dotenv/config node_modules/nodemon/bin/nodemon --watch . --ext ts server",
"lint": "eslint -c .eslintrc.js --ext .ts ./src ",
"test": "echo \"Error: no test specified\" && exit 0"
},
"repository": {
"type": "git",
"url": "https://git.cliffbreak.de/Cliffbreak/CliffbreakTS-Viewer.git"
},
"author": "Simon Giesel",
"license": "ISC",
"dependencies": {
"@nestjs/common": "^7.0.9",
"@nestjs/core": "^7.0.9",
"@nestjs/platform-fastify": "^7.0.9",
"class-transformer": "^0.2.3",
"class-validator": "^0.12.2",
"dotenv": "^8.2.0",
"fastify": "^2.13.1",
"fastify-swagger": "^2.5.1",
"handlebars": "^4.7.6",
"node-ts": "^5.0.4",
"point-of-view": "^3.8.0",
"reflect-metadata": "^0.1.13"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/preset-env": "^7.9.5",
"@nestjs/swagger": "^4.5.3",
"@types/node": "^13.13.2",
"@typescript-eslint/eslint-plugin": "^2.29.0",
"@typescript-eslint/parser": "^2.29.0",
"babel-loader": "^8.1.0",
"concurrently": "^5.2.0",
"dateformat": "^3.0.3",
"del": "^5.1.0",
"eslint": "^6.8.0",
"gulp": "^4.0.2",
"gulp-changed": "^4.0.2",
"gulp-conventional-changelog": "^2.0.29",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-typescript": "^6.0.0-alpha.1",
"gulp-uglifycss": "^1.1.0",
"material-design-icons": "^3.0.1",
"nodemon": "^2.0.3",
"normalize-scss": "^7.0.1",
"ts-node": "^8.8.1",
"typeface-roboto": "0.0.75",
"typescript": "^3.8.3",
"webpack-stream": "^5.2.1"
}
}

2
server/server.js Normal file
View file

@ -0,0 +1,2 @@
require('ts-node/register');
require('./src/server');

View file

@ -0,0 +1,10 @@
import { AppController } from './controllers/app.controller';
import { Module } from '@nestjs/common';
import { TeamspeakService } from './services/teamspeak.service';
@Module({
providers: [TeamspeakService],
controllers: [AppController],
exports: [],
})
export class ApplicationModule { }

View file

@ -0,0 +1,14 @@
import { Controller, Get, Render } from '@nestjs/common';
import { TeamspeakService } from '../services/teamspeak.service';
@Controller()
export class AppController {
constructor(private teamspeakService: TeamspeakService) {}
@Get()
@Render('index.hbs')
async getIndex(): Promise<object> {
const channels = await this.teamspeakService.getPopulatedChannelList();
return { title: 'Cliffbreak.de TS-Viewer', channels };
}
}

View file

@ -0,0 +1,6 @@
export interface IChannel {
id: number;
// parent: number;
children: IChannel[];
name: string;
}

View file

@ -0,0 +1,5 @@
export interface IClient {
id: number;
name: string;
channel: number;
}

View file

@ -0,0 +1,5 @@
import { IChannel } from './channel.interface';
export interface IPopulatedChannel extends IChannel{
clients: string[];
}

View file

@ -0,0 +1,80 @@
import { Injectable, Logger } from '@nestjs/common';
import { IChannel } from '../interfaces/channel.interface';
import { IClient } from '../interfaces/client.interface';
import { IPopulatedChannel } from '../interfaces/populatedchannel.interface';
import { TeamSpeakClient } from 'node-ts';
const env = process.env;
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/camelcase */
// Disable specific ESLint rules because node-ts has no typings
@Injectable()
export class TeamspeakService {
private client: TeamSpeakClient;
constructor() {
this.init();
}
async init(): Promise<void> {
this.client = new TeamSpeakClient(env.TEAMSPEAK_HOST);
try {
await this.client.connect();
await this.client.send('use', { sid: 1 });
await this.client.send('login', {
client_login_name: env.TEAMSPEAK_QUERY_NAME,
client_login_password: env.TEAMSPEAK_QUERY_PASS,
});
} catch (err) {
Logger.error('Error initializing TeamSpeak Server connection', err, 'TeamspeakService');
}
}
async getClients(): Promise<IClient[]> {
const clients: IClient[] = [];
const query = await this.client.send('clientlist', { });
const rawList: any = query.response;
const clientList = rawList.filter(el => el.client_type == 0);
for(const client of clientList)
{
clients.push({ id: client.clid, name: client.client_nickname, channel: client.cid });
}
return clients;
}
async getChannels(): Promise<IChannel[]> {
const channels: IChannel[] = [];
const query = await this.client.send('channellist', {}, []);
const channelList: any = query.response;
for(const channel of channelList) {
if(channel.pid == 0) {
channels.push({ id: channel.cid, children: [], name: channel.channel_name });
} else {
channels.find(el => el.id == channel.pid).children.push({ id: channel.cid, children: [], name: channel.channel_name });
}
}
return channels;
}
async getPopulatedChannelList(): Promise<IPopulatedChannel[]> {
const channels = await this.getChannels();
const clients = await this.getClients();
return this.addClientToChannel(channels, clients);
}
private addClientToChannel(channels, clients): IPopulatedChannel[] {
const channelList: IPopulatedChannel[] = [];
for(const channel of channels) {
const populatedChannel: IPopulatedChannel = channel;
populatedChannel.clients = clients.filter(el=> el.channel == channel.id);
if(channel.children.length > 0) {
this.addClientToChannel(channel.children, clients);
}
channelList.push(populatedChannel);
}
return channelList;
}
}

45
server/src/server.ts Normal file
View file

@ -0,0 +1,45 @@
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
import { ApplicationModule } from './app/app.module';
import { NestFactory } from '@nestjs/core';
import { join } from 'path';
const env = process.env;
const __webapp = join(__dirname, '..', '..', 'webapp');
async function bootstrap(): Promise<void> {
const app = await NestFactory.create<NestFastifyApplication>(
ApplicationModule,
new FastifyAdapter({ logger: false }), // Set to true to activate the built in logger
);
app.useStaticAssets({
root: join(__webapp, 'assets'),
prefix: '/assets/',
});
app.setViewEngine({
engine: {
handlebars: require('handlebars'),
},
templates: join(__webapp, 'src', 'views'),
layout: join('layouts', 'main.hbs'),
options: {
partials: {
'head': join('partials', 'head.hbs'),
'footer': join('partials', 'footer.hbs'),
},
},
});
const swaggerOptions = new DocumentBuilder()
.setTitle('Cliffbreak TeamSpeak API')
.setDescription('This is the official Cliffbreak TeamSpeak API!')
.addBearerAuth()
.setVersion(require('./../package.json').version)
.build();
const swaggerDocument = SwaggerModule.createDocument(app, swaggerOptions);
SwaggerModule.setup('/api-docs', app, swaggerDocument);
await app.listen(parseInt(env.PORT));
}
bootstrap();

21
server/tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"target": "es2017",
"module": "commonjs",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": false,
"declaration": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"noLib": false,
"allowJs": false,
"sourceMap": false,
},
"include": [
"./src/**/*",
],
"exclude": [
"test",
]
}

3
webapp/src/js/app.js Normal file
View file

@ -0,0 +1,3 @@
(async () => {
console.log('app.js loaded successfully')
})();

View file

@ -0,0 +1,14 @@
@import "normalize-scss/sass/normalize/import-now";
// @import "normalize-scss/sass/_normalize";
// @include normalize();
/** COLORS **/
$backgroundColor: #fcfcfc;
body {
font-family: "Roboto";
background-color: $backgroundColor;
}
// @import "animations";

View file

@ -0,0 +1,12 @@
{{#each channels}}
{{this.name}}<br />
{{#each this.clients}}
&nbsp;&nbsp;&nbsp;{{this.name}}<br />
{{/each}}
{{#each this.children}}
&nbsp;&nbsp;&nbsp;{{this.name}}<br />
{{#each this.clients}}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{this.name}}<br />
{{/each}}
{{/each}}
{{/each}}

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
{{>head}}
<body>
<content>
{{{body}}}
</content>
{{!-- {{>footer}} --}}
<script src="/assets/js/app.js" async></script>
</body>
</html>

View file

@ -0,0 +1,10 @@
<footer>
<div class="container">
<copyright>© 2020 Cliffbreak.de</copyright>
{{!-- <div>
<a href="/imprint/">Impressum</a>
|
<a href="/disclaimer/">Haftungsausschluss</a>
</div> --}}
</div>
</footer>

View file

@ -0,0 +1,15 @@
{{!-- NOTE: Don't import page specific scripts here (They will NOT be recalled on page change - see router.js --}}
<head>
<title>{{title}}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" type="text/css" href="/assets/fonts/roboto/roboto.css">
<link rel="stylesheet" type="text/css" href="/assets/fonts/material-icons/material-icons.css">
<link rel="stylesheet" type="text/css" href="/assets/css/index.css">
<noscript>
<link rel="stylesheet" type="text/css" href="/assets/css/noscript.css">
</noscript>
</head>