This commit is contained in:
commit
067996357a
27 changed files with 13845 additions and 0 deletions
47
.drone.yml
Normal file
47
.drone.yml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
kind: pipeline
|
||||||
|
name: default
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: install
|
||||||
|
image: node:13.13
|
||||||
|
commands:
|
||||||
|
- npm --prefix ./server install ./server
|
||||||
|
|
||||||
|
- name: test
|
||||||
|
image: node:13.13
|
||||||
|
commands:
|
||||||
|
- npm --prefix ./server run test
|
||||||
|
|
||||||
|
- name: lint
|
||||||
|
image: node:13.13
|
||||||
|
commands:
|
||||||
|
- npm --prefix ./server run lint
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: node:13.13
|
||||||
|
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/landingpage
|
||||||
|
username:
|
||||||
|
from_secret: docker_username
|
||||||
|
password:
|
||||||
|
from_secret: docker_password
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- tag
|
||||||
|
- deployment
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- master
|
113
.gitignore
vendored
Normal file
113
.gitignore
vendored
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
# ---> 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/
|
||||||
|
mongo/
|
||||||
|
webapp/assets/
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal 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",
|
||||||
|
]
|
||||||
|
}
|
27
.vscode/settings.json
vendored
Normal file
27
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"eslint.workingDirectories": [
|
||||||
|
"./server",
|
||||||
|
"./webapp"
|
||||||
|
],
|
||||||
|
"eslint.format.enable": true,
|
||||||
|
"cSpell.language": "de,en,de-DE,en-US",
|
||||||
|
"cSpell.words": [
|
||||||
|
"Cliffbreak",
|
||||||
|
"Fastify",
|
||||||
|
"Giesel",
|
||||||
|
"Roboto",
|
||||||
|
"browserconfig",
|
||||||
|
"camelcase",
|
||||||
|
"cliffbreakmeet",
|
||||||
|
"dbpath",
|
||||||
|
"favicon",
|
||||||
|
"ijmap",
|
||||||
|
"mkdir",
|
||||||
|
"mongod",
|
||||||
|
"msapplication",
|
||||||
|
"nestjs",
|
||||||
|
"playsinline",
|
||||||
|
"uglifycss"
|
||||||
|
],
|
||||||
|
}
|
78
COMMIT_CONVENTION.md
Normal file
78
COMMIT_CONVENTION.md
Normal 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.
|
121
README.md
Normal file
121
README.md
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
# CliffbreakMeet 💬
|
||||||
|
|
||||||
|
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.
|
||||||
|
Also a working instance of MongoDB `mongod` is required to use all features.
|
||||||
|
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/CliffbreakMeet.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Change to the cloned repository and inside change your active directory to `server`
|
||||||
|
|
||||||
|
```
|
||||||
|
cd CliffbreakMeet && 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 get the database running create a directory "mongo"
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir mongo
|
||||||
|
```
|
||||||
|
|
||||||
|
To start the mongo run
|
||||||
|
|
||||||
|
```
|
||||||
|
cd mongo && mongod --dbpath=.
|
||||||
|
```
|
||||||
|
|
||||||
|
To fill the database with dummy data
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run seed
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
* [MongoDB](https://docs.mongodb.com/) - The database used to store and retrieve data
|
||||||
|
* [HandlebarsJS](https://handlebarsjs.com/) - Dynamic HTML renderer using templates
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
* **Simon Giesel** - *Initial work* - [Simon Giesel](https://git.cliffbreak.de/SimGie)
|
6
server/ .eslintignore
Normal file
6
server/ .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)
|
||||||
|
dist
|
||||||
|
# don't lint nyc coverage output
|
||||||
|
coverage
|
3
server/.env.example
Normal file
3
server/.env.example
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PRODUCTION=false
|
||||||
|
|
||||||
|
PORT=8080
|
89
server/.eslintrc.js
Normal file
89
server/.eslintrc.js
Normal 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
144
server/gulpfile.js
Normal 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;
|
12909
server/package-lock.json
generated
Normal file
12909
server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
62
server/package.json
Normal file
62
server/package.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"name": "cliffbreakmeet",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A self-built video-chat application",
|
||||||
|
"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/CliffbreakMeet.git"
|
||||||
|
},
|
||||||
|
"author": "Simon Giesel",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@nestjs/common": "^6.11.11",
|
||||||
|
"@nestjs/core": "^6.11.11",
|
||||||
|
"@nestjs/platform-fastify": "^6.11.11",
|
||||||
|
"@nestjs/swagger": "^4.5.2",
|
||||||
|
"class-transformer": "^0.2.3",
|
||||||
|
"class-validator": "^0.11.1",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"fastify": "^2.13.1",
|
||||||
|
"fastify-swagger": "^2.5.1",
|
||||||
|
"handlebars": "^4.7.6",
|
||||||
|
"mongoose": "^5.9.9",
|
||||||
|
"point-of-view": "^3.8.0",
|
||||||
|
"reflect-metadata": "^0.1.13"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.9.0",
|
||||||
|
"@babel/preset-env": "^7.9.5",
|
||||||
|
"@types/mongoose": "^5.7.12",
|
||||||
|
"@types/node": "^13.13.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^2.28.0",
|
||||||
|
"@typescript-eslint/parser": "^2.28.0",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"concurrently": "^5.1.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.0.2",
|
||||||
|
"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.2",
|
||||||
|
"typeface-roboto": "0.0.75",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"webpack-stream": "^5.2.1"
|
||||||
|
}
|
||||||
|
}
|
2
server/server.js
Normal file
2
server/server.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
require('ts-node/register');
|
||||||
|
require('./src/server');
|
9
server/src/app/app.module.ts
Normal file
9
server/src/app/app.module.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { AppController } from './controllers/app.controller';
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [],
|
||||||
|
controllers: [AppController],
|
||||||
|
exports: [],
|
||||||
|
})
|
||||||
|
export class ApplicationModule { }
|
26
server/src/app/controllers/app.controller.ts
Normal file
26
server/src/app/controllers/app.controller.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { Controller, Get, HttpCode, Logger, Param, Render } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AppController {
|
||||||
|
// Constructor(){}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
@Render('index.hbs')
|
||||||
|
getIndex(): object {
|
||||||
|
return { message: 'Hello world!' };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':room')
|
||||||
|
@Render('room.hbs')
|
||||||
|
getRoom(@Param('room') roomId: string): object {
|
||||||
|
Logger.log('Client joined room: ' + roomId, 'AppController');
|
||||||
|
return { roomId };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('favicon.ico')
|
||||||
|
@HttpCode(404)
|
||||||
|
getFavicon(): void {
|
||||||
|
// for now do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
server/src/app/schemas/interfaces/user.interface.ts
Normal file
5
server/src/app/schemas/interfaces/user.interface.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { Document } from 'mongoose';
|
||||||
|
|
||||||
|
export interface IUser extends Document {
|
||||||
|
email: string;
|
||||||
|
}
|
45
server/src/server.ts
Normal file
45
server/src/server.ts
Normal 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('CliffbreakMeet API')
|
||||||
|
.setDescription('This is the official CliffbreakMeet 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();
|
23
server/tsconfig.json
Normal file
23
server/tsconfig.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"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/**/*",
|
||||||
|
// "./scripts/setup/init.ts",
|
||||||
|
"./migrations/*",
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"test",
|
||||||
|
]
|
||||||
|
}
|
64
webapp/src/js/app.js
Normal file
64
webapp/src/js/app.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
(async () => {
|
||||||
|
|
||||||
|
// Send permission dialog to client
|
||||||
|
const openMediaDevices = async (constraints) => {
|
||||||
|
return await navigator.mediaDevices.getUserMedia(constraints);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stream = await openMediaDevices({ 'video': true, 'audio': true });
|
||||||
|
console.log('Got MediaStream:', stream);
|
||||||
|
|
||||||
|
function updateList(elements, type) {
|
||||||
|
const listElement = document.querySelector(type == 'video' ? 'select#availableCameras' : 'select#availableMicrophones');
|
||||||
|
listElement.innerHTML = '';
|
||||||
|
elements.forEach(camera => {
|
||||||
|
const cameraOption = document.createElement('option');
|
||||||
|
cameraOption.label = camera.label;
|
||||||
|
cameraOption.value = camera.deviceId;
|
||||||
|
listElement.add(cameraOption);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch an array of devices of a certain type
|
||||||
|
async function getConnectedDevices(type) {
|
||||||
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||||
|
return devices.filter(device => device.kind === type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for changes to media devices and update the list accordingly
|
||||||
|
navigator.mediaDevices.addEventListener('devicechange', async _ => {
|
||||||
|
updateList(await getConnectedDevices('videoinput'), 'video');
|
||||||
|
updateList(await getConnectedDevices('audioinput'), 'audio');
|
||||||
|
});
|
||||||
|
|
||||||
|
updateList(await getConnectedDevices('videoinput'), 'video');
|
||||||
|
updateList(await getConnectedDevices('audioinput'), 'audio');
|
||||||
|
|
||||||
|
|
||||||
|
async function playVideoFromCamera() {
|
||||||
|
try {
|
||||||
|
const videoSelect = document.querySelector('select#availableCameras');
|
||||||
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
video: {
|
||||||
|
deviceId: videoSelect.options[videoSelect.selectedIndex].value,
|
||||||
|
// width: 1920,
|
||||||
|
// height: 1080,
|
||||||
|
frameRate: 30,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const videoElement = document.querySelector('video#localVideo');
|
||||||
|
videoElement.srcObject = stream;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error opening video camera.', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('button#startVideo').addEventListener('click', _ => {
|
||||||
|
playVideoFromCamera();
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error accessing media devices.', error);
|
||||||
|
}
|
||||||
|
})();
|
1
webapp/src/scss/_animations.scss
Normal file
1
webapp/src/scss/_animations.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// Add animation here
|
14
webapp/src/scss/index.scss
Normal file
14
webapp/src/scss/index.scss
Normal 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";
|
1
webapp/src/scss/noscript.scss
Normal file
1
webapp/src/scss/noscript.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// TODO
|
2
webapp/src/views/index.hbs
Normal file
2
webapp/src/views/index.hbs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<h1>This is the Index!</h1>
|
||||||
|
Message: {{message}}
|
13
webapp/src/views/layouts/main.hbs
Normal file
13
webapp/src/views/layouts/main.hbs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
{{>head}}
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<content>
|
||||||
|
{{{body}}}
|
||||||
|
</content>
|
||||||
|
{{>footer}}
|
||||||
|
<script src="/assets/js/app.js" async></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
10
webapp/src/views/partials/footer.hbs
Normal file
10
webapp/src/views/partials/footer.hbs
Normal 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>
|
15
webapp/src/views/partials/head.hbs
Normal file
15
webapp/src/views/partials/head.hbs
Normal 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>
|
7
webapp/src/views/room.hbs
Normal file
7
webapp/src/views/room.hbs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
This is a room
|
||||||
|
|
||||||
|
<p>RoomId: {{roomId}}</p>
|
||||||
|
<select name="availableCameras" id="availableCameras"></select>
|
||||||
|
<select name="availableMicrophones" id="availableMicrophones"></select>
|
||||||
|
<button name="startVideo" id="startVideo">Start Video</button>
|
||||||
|
<video id="localVideo" autoplay playsinline />
|
Loading…
Reference in a new issue