Merge pull request #543 from jc21/develop

v2.4.0
This commit is contained in:
jc21 2020-08-06 16:00:10 +10:00 committed by GitHub
commit 74010acd85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 4826 additions and 4353 deletions

View File

@ -0,0 +1,11 @@
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
}
}
}
}

View File

@ -1 +1 @@
2.3.1 2.4.0

41
Jenkinsfile vendored
View File

@ -83,23 +83,49 @@ pipeline {
''' '''
} }
} }
stage('Test') { stage('Integration Tests Sqlite') {
steps { steps {
// Bring up a stack // Bring up a stack
sh 'docker-compose up -d fullstack' sh 'docker-compose up -d fullstack-sqlite'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack) 120' sh './scripts/wait-healthy $(docker-compose ps -q fullstack-sqlite) 120'
// Run tests // Run tests
sh 'rm -rf test/results' sh 'rm -rf test/results'
sh 'docker-compose up cypress' sh 'docker-compose up cypress-sqlite'
// Get results // Get results
sh 'docker cp -L "$(docker-compose ps -q cypress):/results" test/' sh 'docker cp -L "$(docker-compose ps -q cypress-sqlite):/test/results" test/'
} }
post { post {
always { always {
// Dumps to analyze later // Dumps to analyze later
sh 'mkdir -p debug' sh 'mkdir -p debug'
sh 'docker-compose logs fullstack | gzip > debug/docker_fullstack.log.gz' sh 'docker-compose logs fullstack-sqlite | gzip > debug/docker_fullstack_sqlite.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts
dir(path: 'test/results') {
archiveArtifacts allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml'
}
junit 'test/results/junit/*'
}
}
}
stage('Integration Tests Mysql') {
steps {
// Bring up a stack
sh 'docker-compose up -d fullstack-mysql'
sh './scripts/wait-healthy $(docker-compose ps -q fullstack-mysql) 120'
// Run tests
sh 'rm -rf test/results'
sh 'docker-compose up cypress-mysql'
// Get results
sh 'docker cp -L "$(docker-compose ps -q cypress-mysql):/test/results" test/'
}
post {
always {
// Dumps to analyze later
sh 'mkdir -p debug'
sh 'docker-compose logs fullstack-mysql | gzip > debug/docker_fullstack_mysql.log.gz'
sh 'docker-compose logs db | gzip > debug/docker_db.log.gz' sh 'docker-compose logs db | gzip > debug/docker_db.log.gz'
// Cypress videos and screenshot artifacts // Cypress videos and screenshot artifacts
dir(path: 'test/results') { dir(path: 'test/results') {
@ -136,8 +162,9 @@ pipeline {
} }
steps { steps {
withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) { withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
// Docker Login
sh "docker login -u '${duser}' -p '${dpass}'" sh "docker login -u '${duser}' -p '${dpass}'"
// Buildx with push // Buildx with push from cache
sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}" sh "./scripts/buildx --push ${BUILDX_PUSH_TAGS}"
} }
} }

View File

@ -1,7 +1,7 @@
<p align="center"> <p align="center">
<img src="https://nginxproxymanager.com/github.png"> <img src="https://nginxproxymanager.com/github.png">
<br><br> <br><br>
<img src="https://img.shields.io/badge/version-2.3.1-green.svg?style=for-the-badge"> <img src="https://img.shields.io/badge/version-2.4.0-green.svg?style=for-the-badge">
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager"> <a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge"> <img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
</a> </a>
@ -155,14 +155,24 @@ Special thanks to the following contributors:
<br /><sub><b>OhHeyAlan</b></sub> <br /><sub><b>OhHeyAlan</b></sub>
</a> </a>
</td> </td>
</tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/dogmatic69"> <a href="https://github.com/dogmatic69">
<img src="https://avatars2.githubusercontent.com/u/94674?s=460&u=ca7647de53145c6283b6373ade5dc94ba99347db&v=4" width="80px;" alt=""/> <img src="https://avatars2.githubusercontent.com/u/94674?s=460&u=ca7647de53145c6283b6373ade5dc94ba99347db&v=4" width="80px;" alt=""/>
<br /><sub><b>Carl Sutton</b></sub> <br /><sub><b>Carl Sutton</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/tg44">
<img src="https://avatars0.githubusercontent.com/u/31839?s=460&u=ad32f4cadfef5e5fb09cdfa4b7b7b36a99ba6811&v=4" width="80px;" alt=""/>
<br /><sub><b>Gergő Törcsvári</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/vrenjith">
<img src="https://avatars3.githubusercontent.com/u/2093241?s=460&u=96ce93a9bebabdd0a60a2dc96cd093a41d5edaba&v=4" width="80px;" alt=""/>
<br /><sub><b>vrenjith</b></sub>
</a>
</td>
</tr> </tr>
</table> </table>
<!-- markdownlint-enable --> <!-- markdownlint-enable -->

View File

@ -0,0 +1,26 @@
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/app/backend/config/mydb.sqlite"
},
"pool": {
"min": 0,
"max": 1,
"createTimeoutMillis": 3000,
"acquireTimeoutMillis": 30000,
"idleTimeoutMillis": 30000,
"reapIntervalMillis": 1000,
"createRetryIntervalMillis": 100,
"propagateCreateError": false
},
"migrations": {
"tableName": "migrations",
"stub": "src/backend/lib/migrate_template.js",
"directory": "src/backend/migrations"
}
}
}
}

View File

@ -4,19 +4,27 @@ if (!config.has('database')) {
throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md'); throw new Error('Database config does not exist! Please read the instructions: https://github.com/jc21/nginx-proxy-manager/blob/master/doc/INSTALL.md');
} }
let data = { function generateDbConfig() {
client: config.database.engine, if (config.database.engine === 'knex-native') {
connection: { return config.database.knex;
host: config.database.host, } else
user: config.database.user, return {
password: config.database.password, client: config.database.engine,
database: config.database.name, connection: {
port: config.database.port host: config.database.host,
}, user: config.database.user,
migrations: { password: config.database.password,
tableName: 'migrations' database: config.database.name,
} port: config.database.port
}; },
migrations: {
tableName: 'migrations'
}
};
}
let data = generateDbConfig();
if (typeof config.database.version !== 'undefined') { if (typeof config.database.version !== 'undefined') {
data.version = config.database.version; data.version = config.database.version;

View File

@ -22,22 +22,6 @@ exports.up = function (knex/*, Promise*/) {
}) })
.then(() => { .then(() => {
logger.info('[' + migrate_name + '] setting Table created'); logger.info('[' + migrate_name + '] setting Table created');
// TODO: add settings
let settingModel = require('../models/setting');
return settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {}
});
})
.then(() => {
logger.info('[' + migrate_name + '] Default settings added');
}); });
}; };

View File

@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const AccessListAuth = require('./access_list_auth'); const AccessListAuth = require('./access_list_auth');
const AccessListClient = require('./access_list_client'); const AccessListClient = require('./access_list_client');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class AccessList extends Model { class AccessList extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -21,7 +22,7 @@ class AccessList extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -3,13 +3,14 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class AccessListAuth extends Model { class AccessListAuth extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -18,7 +19,7 @@ class AccessListAuth extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -3,13 +3,14 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class AccessListClient extends Model { class AccessListClient extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -18,7 +19,7 @@ class AccessListClient extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -4,13 +4,14 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class AuditLog extends Model { class AuditLog extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -19,7 +20,7 @@ class AuditLog extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -5,6 +5,7 @@ const bcrypt = require('bcrypt');
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
@ -24,8 +25,8 @@ function encryptPassword () {
class Auth extends Model { class Auth extends Model {
$beforeInsert (queryContext) { $beforeInsert (queryContext) {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -36,7 +37,7 @@ class Auth extends Model {
} }
$beforeUpdate (queryContext) { $beforeUpdate (queryContext) {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
return encryptPassword.apply(this, queryContext); return encryptPassword.apply(this, queryContext);
} }

View File

@ -4,17 +4,18 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class Certificate extends Model { class Certificate extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for expires_on // Default for expires_on
if (typeof this.expires_on === 'undefined') { if (typeof this.expires_on === 'undefined') {
this.expires_on = Model.raw('NOW()'); this.expires_on = now();
} }
// Default for domain_names // Default for domain_names
@ -31,7 +32,7 @@ class Certificate extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Sort domain_names // Sort domain_names
if (typeof this.domain_names !== 'undefined') { if (typeof this.domain_names !== 'undefined') {

View File

@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const Certificate = require('./certificate'); const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class DeadHost extends Model { class DeadHost extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for domain_names // Default for domain_names
if (typeof this.domain_names === 'undefined') { if (typeof this.domain_names === 'undefined') {
@ -27,7 +28,7 @@ class DeadHost extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Sort domain_names // Sort domain_names
if (typeof this.domain_names !== 'undefined') { if (typeof this.domain_names !== 'undefined') {

View File

@ -0,0 +1,13 @@
const db = require('../db');
const config = require('config');
const Model = require('objection').Model;
Model.knex(db);
module.exports = function () {
if (config.database.knex && config.database.knex.client === 'sqlite3') {
return Model.raw('date(\'now\')');
} else {
return Model.raw('NOW()');
}
};

View File

@ -6,13 +6,14 @@ const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const AccessList = require('./access_list'); const AccessList = require('./access_list');
const Certificate = require('./certificate'); const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class ProxyHost extends Model { class ProxyHost extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for domain_names // Default for domain_names
if (typeof this.domain_names === 'undefined') { if (typeof this.domain_names === 'undefined') {
@ -28,7 +29,7 @@ class ProxyHost extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Sort domain_names // Sort domain_names
if (typeof this.domain_names !== 'undefined') { if (typeof this.domain_names !== 'undefined') {

View File

@ -5,13 +5,14 @@ const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const Certificate = require('./certificate'); const Certificate = require('./certificate');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class RedirectionHost extends Model { class RedirectionHost extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for domain_names // Default for domain_names
if (typeof this.domain_names === 'undefined') { if (typeof this.domain_names === 'undefined') {
@ -27,7 +28,7 @@ class RedirectionHost extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Sort domain_names // Sort domain_names
if (typeof this.domain_names !== 'undefined') { if (typeof this.domain_names !== 'undefined') {

View File

@ -4,13 +4,14 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const User = require('./user'); const User = require('./user');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class Stream extends Model { class Stream extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for meta // Default for meta
if (typeof this.meta === 'undefined') { if (typeof this.meta === 'undefined') {
@ -19,7 +20,7 @@ class Stream extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -4,13 +4,14 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const UserPermission = require('./user_permission'); const UserPermission = require('./user_permission');
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class User extends Model { class User extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
// Default for roles // Default for roles
if (typeof this.roles === 'undefined') { if (typeof this.roles === 'undefined') {
@ -19,7 +20,7 @@ class User extends Model {
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -3,17 +3,18 @@
const db = require('../db'); const db = require('../db');
const Model = require('objection').Model; const Model = require('objection').Model;
const now = require('./now_helper');
Model.knex(db); Model.knex(db);
class UserPermission extends Model { class UserPermission extends Model {
$beforeInsert () { $beforeInsert () {
this.created_on = Model.raw('NOW()'); this.created_on = now();
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
$beforeUpdate () { $beforeUpdate () {
this.modified_on = Model.raw('NOW()'); this.modified_on = now();
} }
static get name () { static get name () {

View File

@ -12,22 +12,24 @@
"config": "^3.3.1", "config": "^3.3.1",
"diskdb": "^0.1.17", "diskdb": "^0.1.17",
"express": "^4.17.1", "express": "^4.17.1",
"express-fileupload": "^1.1.6", "express-fileupload": "^1.1.9",
"gravatar": "^1.8.0", "gravatar": "^1.8.0",
"html-entities": "^1.2.1", "html-entities": "^1.2.1",
"json-schema-ref-parser": "^8.0.0", "json-schema-ref-parser": "^8.0.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"knex": "^0.20.13", "knex": "^0.20.13",
"liquidjs": "^9.11.10", "liquidjs": "^9.11.10",
"lodash": "^4.17.15", "lodash": "^4.17.19",
"moment": "^2.24.0", "moment": "^2.24.0",
"mysql": "^2.18.1", "mysql": "^2.18.1",
"node-rsa": "^1.0.8", "node-rsa": "^1.0.8",
"nodemon": "^2.0.2", "nodemon": "^2.0.2",
"objection": "^2.1.3", "objection": "^2.1.3",
"path": "^0.12.7", "path": "^0.12.7",
"pg": "^7.12.1",
"restler": "^3.4.0", "restler": "^3.4.0",
"signale": "^1.4.0", "signale": "^1.4.0",
"sqlite3": "^4.1.1",
"temp-write": "^4.0.0", "temp-write": "^4.0.0",
"unix-timestamp": "^0.2.0" "unix-timestamp": "^0.2.0"
}, },

View File

@ -5,9 +5,15 @@ const logger = require('./logger').setup;
const userModel = require('./models/user'); const userModel = require('./models/user');
const userPermissionModel = require('./models/user_permission'); const userPermissionModel = require('./models/user_permission');
const authModel = require('./models/auth'); const authModel = require('./models/auth');
const settingModel = require('./models/setting');
const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG; const debug_mode = process.env.NODE_ENV !== 'production' || !!process.env.DEBUG;
module.exports = function () { /**
* Creates a new JWT RSA Keypair if not alread set on the config
*
* @returns {Promise}
*/
const setupJwt = () => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// Now go and check if the jwt gpg keys have been created and if not, create them // Now go and check if the jwt gpg keys have been created and if not, create them
if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) { if (!config.has('jwt') || !config.has('jwt.key') || !config.has('jwt.pub')) {
@ -27,12 +33,12 @@ module.exports = function () {
} }
// Now create the keys and save them in the config. // Now create the keys and save them in the config.
let key = new NodeRSA({b: 2048}); let key = new NodeRSA({ b: 2048 });
key.generateKeyPair(); key.generateKeyPair();
config_data.jwt = { config_data.jwt = {
key: key.exportKey('private').toString(), key: key.exportKey('private').toString(),
pub: key.exportKey('public').toString() pub: key.exportKey('public').toString(),
}; };
// Write config // Write config
@ -47,7 +53,6 @@ module.exports = function () {
process.exit(0); process.exit(0);
} }
}); });
} else { } else {
// JWT key pair exists // JWT key pair exists
if (debug_mode) { if (debug_mode) {
@ -56,14 +61,20 @@ module.exports = function () {
resolve(); resolve();
} }
}) });
.then(() => { };
return userModel
.query() /**
.select(userModel.raw('COUNT(`id`) as `count`')) * Creates a default admin users if one doesn't already exist in the database
.where('is_deleted', 0) *
.first(); * @returns {Promise}
}) */
const setupDefaultUser = () => {
return userModel
.query()
.select(userModel.raw('COUNT(`id`) as `count`'))
.where('is_deleted', 0)
.first()
.then((row) => { .then((row) => {
if (!row.count) { if (!row.count) {
// Create a new user and set password // Create a new user and set password
@ -75,7 +86,7 @@ module.exports = function () {
name: 'Administrator', name: 'Administrator',
nickname: 'Admin', nickname: 'Admin',
avatar: '', avatar: '',
roles: ['admin'] roles: ['admin'],
}; };
return userModel return userModel
@ -88,28 +99,64 @@ module.exports = function () {
user_id: user.id, user_id: user.id,
type: 'password', type: 'password',
secret: 'changeme', secret: 'changeme',
meta: {} meta: {},
}) })
.then(() => { .then(() => {
return userPermissionModel return userPermissionModel.query().insert({
.query() user_id: user.id,
.insert({ visibility: 'all',
user_id: user.id, proxy_hosts: 'manage',
visibility: 'all', redirection_hosts: 'manage',
proxy_hosts: 'manage', dead_hosts: 'manage',
redirection_hosts: 'manage', streams: 'manage',
dead_hosts: 'manage', access_lists: 'manage',
streams: 'manage', certificates: 'manage',
access_lists: 'manage', });
certificates: 'manage'
});
}); });
}) })
.then(() => { .then(() => {
logger.info('Initial setup completed'); logger.info('Initial admin setup completed');
}); });
} else if (debug_mode) { } else if (debug_mode) {
logger.debug('Admin user setup not required'); logger.debug('Admin user setup not required');
} }
}); });
}; };
/**
* Creates default settings if they don't already exist in the database
*
* @returns {Promise}
*/
const setupDefaultSettings = () => {
return settingModel
.query()
.select(settingModel.raw('COUNT(`id`) as `count`'))
.where({id: 'default-site'})
.first()
.then((row) => {
if (!row.count) {
settingModel
.query()
.insert({
id: 'default-site',
name: 'Default Site',
description: 'What to show when Nginx is hit with an unknown Host',
value: 'congratulations',
meta: {},
})
.then(() => {
logger.info('Default settings added');
});
}
if (debug_mode) {
logger.debug('Default setting setup not required');
}
});
};
module.exports = function () {
return setupJwt()
.then(setupDefaultUser)
.then(setupDefaultSettings);
};

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,14 @@
version: "3" version: "3"
services: services:
fullstack: fullstack-mysql:
image: ${IMAGE}:ci-${BUILD_NUMBER} image: ${IMAGE}:ci-${BUILD_NUMBER}
environment: environment:
- NODE_ENV=development - NODE_ENV=development
- FORCE_COLOR=1 - FORCE_COLOR=1
volumes: volumes:
- npm_data:/data - npm_data:/data
- ../.jenkins/config.json:/app/config/production.json - ../.jenkins/config-mysql.json:/app/config/development.json
expose: expose:
- 81 - 81
- 80 - 80
@ -17,6 +17,19 @@ services:
depends_on: depends_on:
- db - db
fullstack-sqlite:
image: ${IMAGE}:ci-${BUILD_NUMBER}
environment:
- NODE_ENV=development
- FORCE_COLOR=1
volumes:
- npm_data:/data
- ../.jenkins/config-sqlite.json:/app/config/development.json
expose:
- 81
- 80
- 443
db: db:
image: jc21/mariadb-aria image: jc21/mariadb-aria
environment: environment:
@ -27,13 +40,24 @@ services:
volumes: volumes:
- db_data:/var/lib/mysql - db_data:/var/lib/mysql
cypress: cypress-mysql:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER} image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build: build:
context: ../ context: ../
dockerfile: test/cypress/Dockerfile dockerfile: test/cypress/Dockerfile
environment: environment:
CYPRESS_baseUrl: "http://fullstack:81" CYPRESS_baseUrl: "http://fullstack-mysql:81"
volumes:
- cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}
cypress-sqlite:
image: ${IMAGE}-cypress:ci-${BUILD_NUMBER}
build:
context: ../
dockerfile: test/cypress/Dockerfile
environment:
CYPRESS_baseUrl: "http://fullstack-sqlite:81"
volumes: volumes:
- cypress-logs:/results - cypress-logs:/results
command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json} command: cypress run --browser chrome --config-file=${CYPRESS_CONFIG:-cypress/config/ci.json}

View File

@ -4,15 +4,15 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@vuepress/plugin-google-analytics": "^1.4.0", "@vuepress/plugin-google-analytics": "^1.5.3",
"abbrev": "^1.1.1", "abbrev": "^1.1.1",
"accepts": "^1.3.7", "accepts": "^1.3.7",
"acorn": "^7.1.1", "acorn": "^7.4.0",
"agentkeepalive": "^4.1.0", "agentkeepalive": "^4.1.3",
"ajv": "^6.12.0", "ajv": "^6.12.3",
"ajv-errors": "^1.0.1", "ajv-errors": "^1.0.1",
"ajv-keywords": "^3.4.1", "ajv-keywords": "^3.5.2",
"algoliasearch": "^4.1.0", "algoliasearch": "^4.3.1",
"alphanum-sort": "^1.0.2", "alphanum-sort": "^1.0.2",
"ansi-colors": "^4.1.1", "ansi-colors": "^4.1.1",
"ansi-escapes": "^4.3.1", "ansi-escapes": "^4.3.1",
@ -30,7 +30,7 @@
"array-uniq": "^2.1.0", "array-uniq": "^2.1.0",
"array-unique": "^0.3.2", "array-unique": "^0.3.2",
"asn1": "^0.2.4", "asn1": "^0.2.4",
"asn1.js": "^5.3.0", "asn1.js": "^5.4.1",
"assert": "^2.0.0", "assert": "^2.0.0",
"assert-plus": "^1.0.0", "assert-plus": "^1.0.0",
"assign-symbols": "^2.0.2", "assign-symbols": "^2.0.2",
@ -40,11 +40,11 @@
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
"atob": "^2.1.2", "atob": "^2.1.2",
"autocomplete.js": "^0.37.1", "autocomplete.js": "^0.37.1",
"autoprefixer": "^9.7.6", "autoprefixer": "^9.8.6",
"aws-sign2": "^0.7.0", "aws-sign2": "^0.7.0",
"aws4": "^1.9.1", "aws4": "^1.10.0",
"babel-loader": "^8.1.0", "babel-loader": "^8.1.0",
"babel-plugin-dynamic-import-node": "^2.3.0", "babel-plugin-dynamic-import-node": "^2.3.3",
"babel-plugin-module-resolver": "^4.0.0", "babel-plugin-module-resolver": "^4.0.0",
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"base": "^3.0.0", "base": "^3.0.0",
@ -52,9 +52,9 @@
"batch": "^0.6.1", "batch": "^0.6.1",
"bcrypt-pbkdf": "^1.0.2", "bcrypt-pbkdf": "^1.0.2",
"big.js": "^5.2.2", "big.js": "^5.2.2",
"binary-extensions": "^2.0.0", "binary-extensions": "^2.1.0",
"bluebird": "^3.7.2", "bluebird": "^3.7.2",
"bn.js": "^5.1.1", "bn.js": "^5.1.2",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"bonjour": "^3.5.0", "bonjour": "^3.5.0",
"boolbase": "^1.0.0", "boolbase": "^1.0.0",
@ -65,18 +65,18 @@
"browserify-cipher": "^1.0.1", "browserify-cipher": "^1.0.1",
"browserify-des": "^1.0.2", "browserify-des": "^1.0.2",
"browserify-rsa": "^4.0.1", "browserify-rsa": "^4.0.1",
"browserify-sign": "^4.0.4", "browserify-sign": "^4.2.1",
"browserify-zlib": "^0.2.0", "browserify-zlib": "^0.2.0",
"browserslist": "^4.11.1", "browserslist": "^4.13.0",
"buffer": "^5.5.0", "buffer": "^5.6.0",
"buffer-from": "^1.1.1", "buffer-from": "^1.1.1",
"buffer-indexof": "^1.1.1", "buffer-indexof": "^1.1.1",
"buffer-json": "^2.0.0", "buffer-json": "^2.0.0",
"buffer-xor": "^2.0.2", "buffer-xor": "^2.0.2",
"builtin-status-codes": "^3.0.0", "builtin-status-codes": "^3.0.0",
"bytes": "^3.1.0", "bytes": "^3.1.0",
"cac": "^6.5.8", "cac": "^6.6.1",
"cacache": "^15.0.0", "cacache": "^15.0.5",
"cache-base": "^4.0.0", "cache-base": "^4.0.0",
"cache-loader": "^4.1.0", "cache-loader": "^4.1.0",
"call-me-maybe": "^1.0.1", "call-me-maybe": "^1.0.1",
@ -84,12 +84,12 @@
"caller-path": "^3.0.0", "caller-path": "^3.0.0",
"callsites": "^3.1.0", "callsites": "^3.1.0",
"camel-case": "^4.1.1", "camel-case": "^4.1.1",
"camelcase": "^5.3.1", "camelcase": "^6.0.0",
"caniuse-api": "^3.0.0", "caniuse-api": "^3.0.0",
"caniuse-lite": "^1.0.30001039", "caniuse-lite": "^1.0.30001111",
"caseless": "^0.12.0", "caseless": "^0.12.0",
"chalk": "^4.0.0", "chalk": "^4.1.0",
"chokidar": "^3.3.1", "chokidar": "^3.4.1",
"chownr": "^2.0.0", "chownr": "^2.0.0",
"chrome-trace-event": "^1.0.2", "chrome-trace-event": "^1.0.2",
"ci-info": "^2.0.0", "ci-info": "^2.0.0",
@ -106,7 +106,7 @@
"color-name": "^1.1.4", "color-name": "^1.1.4",
"color-string": "^1.5.3", "color-string": "^1.5.3",
"combined-stream": "^1.0.8", "combined-stream": "^1.0.8",
"commander": "^5.0.0", "commander": "^6.0.0",
"commondir": "^1.0.1", "commondir": "^1.0.1",
"component-emitter": "^1.3.0", "component-emitter": "^1.3.0",
"compressible": "^2.0.18", "compressible": "^2.0.18",
@ -114,36 +114,36 @@
"concat-map": "^0.0.1", "concat-map": "^0.0.1",
"concat-stream": "^2.0.0", "concat-stream": "^2.0.0",
"connect-history-api-fallback": "^1.6.0", "connect-history-api-fallback": "^1.6.0",
"consola": "^2.11.3", "consola": "^2.15.0",
"console-browserify": "^1.2.0", "console-browserify": "^1.2.0",
"consolidate": "^0.15.1", "consolidate": "^0.15.1",
"constants-browserify": "^1.0.0", "constants-browserify": "^1.0.0",
"content-disposition": "^0.5.3", "content-disposition": "^0.5.3",
"content-type": "^1.0.4", "content-type": "^1.0.4",
"convert-source-map": "^1.7.0", "convert-source-map": "^1.7.0",
"cookie": "^0.4.0", "cookie": "^0.4.1",
"cookie-signature": "^1.1.0", "cookie-signature": "^1.1.0",
"copy-concurrently": "^1.0.5", "copy-concurrently": "^1.0.5",
"copy-descriptor": "^0.1.1", "copy-descriptor": "^0.1.1",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^6.0.3",
"core-js": "^3.6.4", "core-js": "^3.6.5",
"core-util-is": "^1.0.2", "core-util-is": "^1.0.2",
"cosmiconfig": "^6.0.0", "cosmiconfig": "^7.0.0",
"create-ecdh": "^4.0.3", "create-ecdh": "^4.0.4",
"create-hash": "^1.2.0", "create-hash": "^1.2.0",
"create-hmac": "^1.1.7", "create-hmac": "^1.1.7",
"cross-spawn": "^7.0.2", "cross-spawn": "^7.0.3",
"crypto-browserify": "^3.12.0", "crypto-browserify": "^3.12.0",
"css": "^2.2.4", "css": "^3.0.0",
"css-color-names": "^1.0.1", "css-color-names": "^1.0.1",
"css-declaration-sorter": "^5.1.2", "css-declaration-sorter": "^5.1.2",
"css-loader": "^3.5.0", "css-loader": "^4.2.0",
"css-parse": "^2.0.0", "css-parse": "^2.0.0",
"css-select": "^2.1.0", "css-select": "^2.1.0",
"css-select-base-adapter": "^0.1.1", "css-select-base-adapter": "^0.1.1",
"css-tree": "^1.0.0-alpha.39", "css-tree": "^1.0.0-alpha.39",
"css-unit-converter": "^1.1.1", "css-unit-converter": "^1.1.2",
"css-what": "^3.2.1", "css-what": "^3.3.0",
"cssesc": "^3.0.0", "cssesc": "^3.0.0",
"cssnano": "^4.1.10", "cssnano": "^4.1.10",
"cssnano-preset-default": "^4.0.7", "cssnano-preset-default": "^4.0.7",
@ -158,9 +158,9 @@
"debug": "^4.1.1", "debug": "^4.1.1",
"decamelize": "^4.0.0", "decamelize": "^4.0.0",
"decode-uri-component": "^0.2.0", "decode-uri-component": "^0.2.0",
"deep-equal": "^2.0.2", "deep-equal": "^2.0.3",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"default-gateway": "^6.0.0", "default-gateway": "^6.0.1",
"define-properties": "^1.1.3", "define-properties": "^1.1.3",
"define-property": "^2.0.2", "define-property": "^2.0.2",
"del": "^5.1.0", "del": "^5.1.0",
@ -178,52 +178,52 @@
"dns-txt": "^2.0.2", "dns-txt": "^2.0.2",
"docsearch.js": "^2.6.3", "docsearch.js": "^2.6.3",
"dom-converter": "^0.2.0", "dom-converter": "^0.2.0",
"dom-serializer": "^0.2.2", "dom-serializer": "^1.0.1",
"dom-walk": "^0.1.2", "dom-walk": "^0.1.2",
"domain-browser": "^4.0.0", "domain-browser": "^4.16.0",
"domelementtype": "^2.0.1", "domelementtype": "^2.0.1",
"domhandler": "^3.0.0", "domhandler": "^3.0.0",
"domutils": "^2.0.0", "domutils": "^2.1.0",
"dot-prop": "^5.2.0", "dot-prop": "^5.2.0",
"duplexify": "^4.1.1", "duplexify": "^4.1.1",
"ecc-jsbn": "^0.2.0", "ecc-jsbn": "^0.2.0",
"ee-first": "^1.1.1", "ee-first": "^1.1.1",
"electron-to-chromium": "^1.3.397", "electron-to-chromium": "^1.3.522",
"elliptic": "^6.5.2", "elliptic": "^6.5.3",
"emoji-regex": "^8.0.0", "emoji-regex": "^9.0.0",
"emojis-list": "^3.0.0", "emojis-list": "^3.0.0",
"encodeurl": "^1.0.2", "encodeurl": "^1.0.2",
"end-of-stream": "^1.4.4", "end-of-stream": "^1.4.4",
"enhanced-resolve": "^4.1.1", "enhanced-resolve": "^4.3.0",
"entities": "^2.0.0", "entities": "^2.0.3",
"envify": "^4.1.0", "envify": "^4.1.0",
"envinfo": "^7.5.0", "envinfo": "^7.7.2",
"errno": "^0.1.7", "errno": "^0.1.7",
"error-ex": "^1.3.2", "error-ex": "^1.3.2",
"es-abstract": "^1.17.5", "es-abstract": "^1.17.6",
"es-to-primitive": "^1.2.1", "es-to-primitive": "^1.2.1",
"es6-promise": "^4.2.8", "es6-promise": "^4.2.8",
"escape-html": "^1.0.3", "escape-html": "^1.0.3",
"escape-string-regexp": "^2.0.0", "escape-string-regexp": "^4.0.0",
"eslint-scope": "^5.0.0", "eslint-scope": "^5.1.0",
"esprima": "^4.0.1", "esprima": "^4.0.1",
"esrecurse": "^4.2.1", "esrecurse": "^4.2.1",
"estraverse": "^5.0.0", "estraverse": "^5.2.0",
"esutils": "^2.0.3", "esutils": "^2.0.3",
"etag": "^1.8.1", "etag": "^1.8.1",
"eventemitter3": "^4.0.0", "eventemitter3": "^4.0.4",
"events": "^3.1.0", "events": "^3.2.0",
"eventsource": "^1.0.7", "eventsource": "^1.0.7",
"evp_bytestokey": "^1.0.3", "evp_bytestokey": "^1.0.3",
"execa": "^4.0.0", "execa": "^4.0.3",
"expand-brackets": "^4.0.0", "expand-brackets": "^4.0.0",
"express": "^4.17.1", "express": "^4.17.1",
"extend": "^3.0.2", "extend": "^3.0.2",
"extend-shallow": "^3.0.2", "extend-shallow": "^3.0.2",
"extglob": "^3.0.0", "extglob": "^3.0.0",
"extsprintf": "^1.4.0", "extsprintf": "^1.4.0",
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.3",
"fast-glob": "^3.2.2", "fast-glob": "^3.2.4",
"fast-json-stable-stringify": "^2.1.0", "fast-json-stable-stringify": "^2.1.0",
"faye-websocket": "^0.11.3", "faye-websocket": "^0.11.3",
"figgy-pudding": "^3.5.2", "figgy-pudding": "^3.5.2",
@ -235,7 +235,7 @@
"find-cache-dir": "^3.3.1", "find-cache-dir": "^3.3.1",
"find-up": "^4.1.0", "find-up": "^4.1.0",
"flush-write-stream": "^2.0.0", "flush-write-stream": "^2.0.0",
"follow-redirects": "^1.11.0", "follow-redirects": "^1.12.1",
"for-in": "^1.0.2", "for-in": "^1.0.2",
"foreach": "^2.0.5", "foreach": "^2.0.5",
"forever-agent": "^0.6.1", "forever-agent": "^0.6.1",
@ -244,7 +244,7 @@
"fragment-cache": "^0.2.1", "fragment-cache": "^0.2.1",
"fresh": "^0.5.2", "fresh": "^0.5.2",
"from2": "^2.3.0", "from2": "^2.3.0",
"fs-extra": "^9.0.0", "fs-extra": "^9.0.1",
"fs-write-stream-atomic": "^1.0.10", "fs-write-stream-atomic": "^1.0.10",
"fs.realpath": "^1.0.0", "fs.realpath": "^1.0.0",
"function-bind": "^1.1.1", "function-bind": "^1.1.1",
@ -257,21 +257,21 @@
"glob-parent": "^5.1.1", "glob-parent": "^5.1.1",
"glob-to-regexp": "^0.4.1", "glob-to-regexp": "^0.4.1",
"global": "^4.4.0", "global": "^4.4.0",
"globals": "^12.4.0", "globals": "^13.1.0",
"globby": "^11.0.0", "globby": "^11.0.1",
"good-listener": "^1.2.2", "good-listener": "^1.2.2",
"graceful-fs": "^4.2.3", "graceful-fs": "^4.2.4",
"gray-matter": "^4.0.2", "gray-matter": "^4.0.2",
"handle-thing": "^2.0.1", "handle-thing": "^2.0.1",
"har-schema": "^2.0.0", "har-schema": "^2.0.0",
"har-validator": "^5.1.3", "har-validator": "^5.1.5",
"has": "^1.0.3", "has": "^1.0.3",
"has-ansi": "^4.0.0", "has-ansi": "^4.0.0",
"has-flag": "^4.0.0", "has-flag": "^4.0.0",
"has-symbols": "^1.0.1", "has-symbols": "^1.0.1",
"has-value": "^2.0.2", "has-value": "^2.0.2",
"has-values": "^2.0.1", "has-values": "^2.0.1",
"hash-base": "^3.0.4", "hash-base": "^3.1.0",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
"hash.js": "^1.1.7", "hash.js": "^1.1.7",
"he": "^1.2.0", "he": "^1.2.0",
@ -282,24 +282,24 @@
"hsl-regex": "^1.0.0", "hsl-regex": "^1.0.0",
"hsla-regex": "^1.0.0", "hsla-regex": "^1.0.0",
"html-comment-regex": "^1.1.2", "html-comment-regex": "^1.1.2",
"html-entities": "^1.2.1", "html-entities": "^1.3.1",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",
"html-tags": "^3.1.0", "html-tags": "^3.1.0",
"htmlparser2": "^4.1.0", "htmlparser2": "^4.1.0",
"http-deceiver": "^1.2.7", "http-deceiver": "^1.2.7",
"http-errors": "^1.7.3", "http-errors": "^1.8.0",
"http-parser-js": "^0.5.2", "http-parser-js": "^0.5.2",
"http-proxy": "^1.18.0", "http-proxy": "^1.18.1",
"http-proxy-middleware": "^1.0.3", "http-proxy-middleware": "^1.0.5",
"http-signature": "^1.3.4", "http-signature": "^1.3.4",
"https-browserify": "^1.0.0", "https-browserify": "^1.0.0",
"iconv-lite": "^0.5.1", "iconv-lite": "^0.6.2",
"icss-replace-symbols": "^1.1.0", "icss-replace-symbols": "^1.1.0",
"icss-utils": "^4.1.1", "icss-utils": "^4.1.1",
"ieee754": "^1.1.13", "ieee754": "^1.1.13",
"iferr": "^1.0.2", "iferr": "^1.0.2",
"ignore": "^5.1.4", "ignore": "^5.1.8",
"immediate": "^3.2.3", "immediate": "^3.3.0",
"import-cwd": "^3.0.0", "import-cwd": "^3.0.0",
"import-fresh": "^3.2.1", "import-fresh": "^3.2.1",
"import-from": "^3.0.0", "import-from": "^3.0.0",
@ -309,9 +309,9 @@
"infer-owner": "^1.0.4", "infer-owner": "^1.0.4",
"inflight": "^1.0.6", "inflight": "^1.0.6",
"inherits": "^2.0.4", "inherits": "^2.0.4",
"internal-ip": "^6.0.0", "internal-ip": "^6.1.0",
"invariant": "^2.2.4", "invariant": "^2.2.4",
"invert-kv": "^3.0.0", "invert-kv": "^3.0.1",
"ip": "^1.1.5", "ip": "^1.1.5",
"ip-regex": "^4.1.0", "ip-regex": "^4.1.0",
"ipaddr.js": "^1.9.1", "ipaddr.js": "^1.9.1",
@ -321,7 +321,7 @@
"is-arrayish": "^0.3.2", "is-arrayish": "^0.3.2",
"is-binary-path": "^2.1.0", "is-binary-path": "^2.1.0",
"is-buffer": "^2.0.4", "is-buffer": "^2.0.4",
"is-callable": "^1.1.5", "is-callable": "^1.2.0",
"is-color-stop": "^1.1.0", "is-color-stop": "^1.1.0",
"is-data-descriptor": "^2.0.0", "is-data-descriptor": "^2.0.0",
"is-date-object": "^1.0.2", "is-date-object": "^1.0.2",
@ -337,25 +337,25 @@
"is-path-in-cwd": "^3.0.0", "is-path-in-cwd": "^3.0.0",
"is-path-inside": "^3.0.2", "is-path-inside": "^3.0.2",
"is-plain-obj": "^2.1.0", "is-plain-obj": "^2.1.0",
"is-plain-object": "^3.0.0", "is-plain-object": "^4.1.1",
"is-regex": "^1.0.5", "is-regex": "^1.1.1",
"is-resolvable": "^1.1.0", "is-resolvable": "^1.1.0",
"is-stream": "^2.0.0", "is-stream": "^2.0.0",
"is-svg": "^4.2.1", "is-svg": "^4.2.1",
"is-symbol": "^1.0.3", "is-symbol": "^1.0.3",
"is-typedarray": "^1.0.0", "is-typedarray": "^1.0.0",
"is-windows": "^1.0.2", "is-windows": "^1.0.2",
"is-wsl": "^2.1.1", "is-wsl": "^2.2.0",
"isarray": "^2.0.5", "isarray": "^2.0.5",
"isexe": "^2.0.0", "isexe": "^2.0.0",
"isobject": "^4.0.0", "isobject": "^4.0.0",
"isstream": "^0.1.2", "isstream": "^0.1.2",
"javascript-stringify": "^2.0.1", "javascript-stringify": "^2.0.1",
"js-levenshtein": "^1.1.6", "js-levenshtein": "^1.1.6",
"js-tokens": "^5.0.0", "js-tokens": "^6.0.0",
"js-yaml": "^3.13.1", "js-yaml": "^3.14.0",
"jsbn": "^1.1.0", "jsbn": "^1.1.0",
"jsesc": "^2.5.2", "jsesc": "^3.0.1",
"json-parse-better-errors": "^1.0.2", "json-parse-better-errors": "^1.0.2",
"json-schema": "^0.2.5", "json-schema": "^0.2.5",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
@ -368,12 +368,12 @@
"kind-of": "^6.0.3", "kind-of": "^6.0.3",
"last-call-webpack-plugin": "^3.0.0", "last-call-webpack-plugin": "^3.0.0",
"lcid": "^3.1.1", "lcid": "^3.1.1",
"linkify-it": "^2.2.0", "linkify-it": "^3.0.2",
"load-script": "^1.0.0", "load-script": "^1.0.0",
"loader-runner": "^3.1.0", "loader-runner": "^4.0.0",
"loader-utils": "^2.0.0", "loader-utils": "^2.0.0",
"locate-path": "^5.0.0", "locate-path": "^5.0.0",
"lodash": "^4.17.15", "lodash": "^4.17.19",
"lodash._reinterpolate": "^3.0.0", "lodash._reinterpolate": "^3.0.0",
"lodash.chunk": "^4.2.0", "lodash.chunk": "^4.2.0",
"lodash.clonedeep": "^4.5.0", "lodash.clonedeep": "^4.5.0",
@ -385,37 +385,37 @@
"lodash.template": "^4.5.0", "lodash.template": "^4.5.0",
"lodash.templatesettings": "^4.2.0", "lodash.templatesettings": "^4.2.0",
"lodash.uniq": "^4.5.0", "lodash.uniq": "^4.5.0",
"loglevel": "^1.6.7", "loglevel": "^1.6.8",
"loose-envify": "^1.4.0", "loose-envify": "^1.4.0",
"lower-case": "^2.0.1", "lower-case": "^2.0.1",
"lru-cache": "^5.1.1", "lru-cache": "^6.0.0",
"make-dir": "^3.0.2", "make-dir": "^3.1.0",
"mamacro": "^0.0.7", "mamacro": "^0.0.7",
"map-age-cleaner": "^0.1.3", "map-age-cleaner": "^0.1.3",
"map-cache": "^0.2.2", "map-cache": "^0.2.2",
"map-visit": "^1.0.0", "map-visit": "^1.0.0",
"markdown-it": "^10.0.0", "markdown-it": "^11.0.0",
"markdown-it-anchor": "^5.2.7", "markdown-it-anchor": "^5.3.0",
"markdown-it-chain": "^1.3.0", "markdown-it-chain": "^1.3.0",
"markdown-it-container": "^2.0.0", "markdown-it-container": "^3.0.0",
"markdown-it-emoji": "^1.4.0", "markdown-it-emoji": "^1.4.0",
"markdown-it-table-of-contents": "^0.4.4", "markdown-it-table-of-contents": "^0.4.4",
"md5.js": "^1.3.5", "md5.js": "^1.3.5",
"mdn-data": "^2.0.8", "mdn-data": "^2.0.11",
"mdurl": "^1.0.1", "mdurl": "^1.0.1",
"media-typer": "^1.1.0", "media-typer": "^1.1.0",
"mem": "^6.0.1", "mem": "^6.1.0",
"memory-fs": "^0.5.0", "memory-fs": "^0.5.0",
"merge-descriptors": "^1.0.1", "merge-descriptors": "^1.0.1",
"merge-source-map": "^1.1.0", "merge-source-map": "^1.1.0",
"merge2": "^1.3.0", "merge2": "^1.4.1",
"methods": "^1.1.2", "methods": "^1.1.2",
"micromatch": "^4.0.2", "micromatch": "^4.0.2",
"miller-rabin": "^4.0.1", "miller-rabin": "^4.0.1",
"mime": "^2.4.4", "mime": "^2.4.6",
"mime-db": "^1.43.0", "mime-db": "^1.44.0",
"mime-types": "^2.1.26", "mime-types": "^2.1.27",
"mimic-fn": "^3.0.0", "mimic-fn": "^3.1.0",
"min-document": "^2.19.0", "min-document": "^2.19.0",
"mini-css-extract-plugin": "^0.9.0", "mini-css-extract-plugin": "^0.9.0",
"minimalistic-assert": "^1.0.1", "minimalistic-assert": "^1.0.1",
@ -431,16 +431,16 @@
"multicast-dns-service-types": "^1.1.0", "multicast-dns-service-types": "^1.1.0",
"nanomatch": "^1.2.13", "nanomatch": "^1.2.13",
"negotiator": "^0.6.2", "negotiator": "^0.6.2",
"neo-async": "^2.6.1", "neo-async": "^2.6.2",
"nice-try": "^2.0.1", "nice-try": "^2.0.1",
"no-case": "^3.0.3", "no-case": "^3.0.3",
"node-forge": "^0.9.1", "node-forge": "^0.9.1",
"node-libs-browser": "^2.2.1", "node-libs-browser": "^2.2.1",
"node-releases": "^1.1.53", "node-releases": "^1.1.60",
"nopt": "^4.0.3", "nopt": "^4.0.3",
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
"normalize-range": "^0.1.2", "normalize-range": "^0.1.2",
"normalize-url": "^5.0.0", "normalize-url": "^5.1.0",
"npm-run-path": "^4.0.1", "npm-run-path": "^4.0.1",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"nth-check": "^1.0.2", "nth-check": "^1.0.2",
@ -449,8 +449,8 @@
"oauth-sign": "^0.9.0", "oauth-sign": "^0.9.0",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"object-copy": "^1.0.0", "object-copy": "^1.0.0",
"object-inspect": "^1.7.0", "object-inspect": "^1.8.0",
"object-is": "^1.0.2", "object-is": "^1.1.2",
"object-keys": "^1.1.1", "object-keys": "^1.1.1",
"object-visit": "^1.0.1", "object-visit": "^1.0.1",
"object.assign": "^4.1.0", "object.assign": "^4.1.0",
@ -461,7 +461,7 @@
"on-finished": "^2.3.0", "on-finished": "^2.3.0",
"on-headers": "^1.0.2", "on-headers": "^1.0.2",
"once": "^1.4.0", "once": "^1.4.0",
"opencollective-postinstall": "^2.0.2", "opencollective-postinstall": "^2.0.3",
"opn": "^6.0.0", "opn": "^6.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.3", "optimize-css-assets-webpack-plugin": "^5.0.3",
"original": "^1.0.2", "original": "^1.0.2",
@ -470,7 +470,7 @@
"p-defer": "^3.0.0", "p-defer": "^3.0.0",
"p-finally": "^2.0.1", "p-finally": "^2.0.1",
"p-is-promise": "^3.0.0", "p-is-promise": "^3.0.0",
"p-limit": "^2.3.0", "p-limit": "^3.0.2",
"p-locate": "^4.1.0", "p-locate": "^4.1.0",
"p-map": "^4.0.0", "p-map": "^4.0.0",
"p-retry": "^4.2.0", "p-retry": "^4.2.0",
@ -479,7 +479,7 @@
"parallel-transform": "^1.2.0", "parallel-transform": "^1.2.0",
"param-case": "^3.0.3", "param-case": "^3.0.3",
"parse-asn1": "^5.1.5", "parse-asn1": "^5.1.5",
"parse-json": "^5.0.0", "parse-json": "^5.0.1",
"parseurl": "^1.3.3", "parseurl": "^1.3.3",
"pascalcase": "^1.0.0", "pascalcase": "^1.0.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
@ -491,16 +491,16 @@
"path-parse": "^1.0.6", "path-parse": "^1.0.6",
"path-to-regexp": "^6.1.0", "path-to-regexp": "^6.1.0",
"path-type": "^4.0.0", "path-type": "^4.0.0",
"pbkdf2": "^3.0.17", "pbkdf2": "^3.1.1",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"pify": "^5.0.0", "pify": "^5.0.0",
"pinkie": "^2.0.4", "pinkie": "^2.0.4",
"pinkie-promise": "^2.0.1", "pinkie-promise": "^2.0.1",
"pkg-dir": "^4.2.0", "pkg-dir": "^4.2.0",
"pkg-up": "^3.1.0", "pkg-up": "^3.1.0",
"portfinder": "^1.0.25", "portfinder": "^1.0.28",
"posix-character-classes": "^1.0.0", "posix-character-classes": "^1.0.0",
"postcss": "^7.0.27", "postcss": "^7.0.32",
"postcss-calc": "^7.0.2", "postcss-calc": "^7.0.2",
"postcss-colormin": "^4.0.3", "postcss-colormin": "^4.0.3",
"postcss-convert-values": "^4.0.1", "postcss-convert-values": "^4.0.1",
@ -517,7 +517,7 @@
"postcss-minify-params": "^4.0.2", "postcss-minify-params": "^4.0.2",
"postcss-minify-selectors": "^4.0.2", "postcss-minify-selectors": "^4.0.2",
"postcss-modules-extract-imports": "^2.0.0", "postcss-modules-extract-imports": "^2.0.0",
"postcss-modules-local-by-default": "^3.0.2", "postcss-modules-local-by-default": "^3.0.3",
"postcss-modules-scope": "^2.2.0", "postcss-modules-scope": "^2.2.0",
"postcss-modules-values": "^3.0.0", "postcss-modules-values": "^3.0.0",
"postcss-normalize-charset": "^4.0.1", "postcss-normalize-charset": "^4.0.1",
@ -536,9 +536,9 @@
"postcss-selector-parser": "^6.0.2", "postcss-selector-parser": "^6.0.2",
"postcss-svgo": "^4.0.2", "postcss-svgo": "^4.0.2",
"postcss-unique-selectors": "^4.0.1", "postcss-unique-selectors": "^4.0.1",
"postcss-value-parser": "^4.0.3", "postcss-value-parser": "^4.1.0",
"prepend-http": "^3.0.1", "prepend-http": "^3.0.1",
"prettier": "^2.0.4", "prettier": "^2.0.5",
"pretty-error": "^2.1.1", "pretty-error": "^2.1.1",
"pretty-time": "^1.1.0", "pretty-time": "^1.1.0",
"prismjs": "^1.20.0", "prismjs": "^1.20.0",
@ -555,8 +555,8 @@
"pumpify": "^2.0.1", "pumpify": "^2.0.1",
"punycode": "^2.1.1", "punycode": "^2.1.1",
"q": "^1.5.1", "q": "^1.5.1",
"qs": "^6.9.3", "qs": "^6.9.4",
"query-string": "^6.12.0", "query-string": "^6.13.1",
"querystring": "^0.2.0", "querystring": "^0.2.0",
"querystring-es3": "^0.2.1", "querystring-es3": "^0.2.1",
"querystringify": "^2.1.1", "querystringify": "^2.1.1",
@ -567,14 +567,14 @@
"readable-stream": "^3.6.0", "readable-stream": "^3.6.0",
"readdirp": "^3.4.0", "readdirp": "^3.4.0",
"reduce": "^1.0.2", "reduce": "^1.0.2",
"regenerate": "^1.4.0", "regenerate": "^1.4.1",
"regenerate-unicode-properties": "^8.2.0", "regenerate-unicode-properties": "^8.2.0",
"regenerator-runtime": "^0.13.5", "regenerator-runtime": "^0.13.7",
"regenerator-transform": "^0.14.4", "regenerator-transform": "^0.14.5",
"regex-not": "^1.0.2", "regex-not": "^1.0.2",
"regexp.prototype.flags": "^1.3.0", "regexp.prototype.flags": "^1.3.0",
"regexpu-core": "^4.7.0", "regexpu-core": "^4.7.0",
"regjsgen": "^0.5.1", "regjsgen": "^0.5.2",
"regjsparser": "^0.6.4", "regjsparser": "^0.6.4",
"relateurl": "^0.2.7", "relateurl": "^0.2.7",
"remove-trailing-separator": "^1.1.0", "remove-trailing-separator": "^1.1.0",
@ -586,7 +586,7 @@
"require-main-filename": "^2.0.0", "require-main-filename": "^2.0.0",
"requires-port": "^1.0.0", "requires-port": "^1.0.0",
"reselect": "^4.0.0", "reselect": "^4.0.0",
"resolve": "^1.15.1", "resolve": "^1.17.0",
"resolve-cwd": "^3.0.0", "resolve-cwd": "^3.0.0",
"resolve-from": "^5.0.0", "resolve-from": "^5.0.0",
"resolve-url": "^0.2.1", "resolve-url": "^0.2.1",
@ -597,18 +597,18 @@
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ripemd160": "^2.0.2", "ripemd160": "^2.0.2",
"run-queue": "^2.0.1", "run-queue": "^2.0.1",
"safe-buffer": "^5.2.0", "safe-buffer": "^5.2.1",
"safe-regex": "^2.1.1", "safe-regex": "^2.1.1",
"safer-buffer": "^2.1.2", "safer-buffer": "^2.1.2",
"sax": "^1.2.4", "sax": "^1.2.4",
"schema-utils": "^2.6.5", "schema-utils": "^2.7.0",
"section-matter": "^1.0.0", "section-matter": "^1.0.0",
"select": "^1.1.2", "select": "^1.1.2",
"select-hose": "^2.0.0", "select-hose": "^2.0.0",
"selfsigned": "^1.10.7", "selfsigned": "^1.10.7",
"semver": "^7.2.1", "semver": "^7.3.2",
"send": "^0.17.1", "send": "^0.17.1",
"serialize-javascript": "^3.0.0", "serialize-javascript": "^4.0.0",
"serve-index": "^1.9.1", "serve-index": "^1.9.1",
"serve-static": "^1.14.1", "serve-static": "^1.14.1",
"set-blocking": "^2.0.0", "set-blocking": "^2.0.0",
@ -620,19 +620,19 @@
"shebang-regex": "^3.0.0", "shebang-regex": "^3.0.0",
"signal-exit": "^3.0.3", "signal-exit": "^3.0.3",
"simple-swizzle": "^0.2.2", "simple-swizzle": "^0.2.2",
"sitemap": "^6.1.0", "sitemap": "^6.2.0",
"slash": "^3.0.0", "slash": "^3.0.0",
"smoothscroll-polyfill": "^0.4.4", "smoothscroll-polyfill": "^0.4.4",
"snapdragon": "^0.12.0", "snapdragon": "^0.12.0",
"snapdragon-node": "^3.0.0", "snapdragon-node": "^3.0.0",
"snapdragon-util": "^5.0.1", "snapdragon-util": "^5.0.1",
"sockjs": "^0.3.20", "sockjs": "^0.3.21",
"sockjs-client": "^1.4.0", "sockjs-client": "^1.5.0",
"sort-keys": "^4.0.0", "sort-keys": "^4.0.0",
"source-list-map": "^2.0.1", "source-list-map": "^2.0.1",
"source-map": "^0.7.3", "source-map": "^0.7.3",
"source-map-resolve": "^0.6.0", "source-map-resolve": "^0.6.0",
"source-map-support": "^0.5.16", "source-map-support": "^0.5.19",
"source-map-url": "^0.4.0", "source-map-url": "^0.4.0",
"spdy": "^4.0.2", "spdy": "^4.0.2",
"spdy-transport": "^3.0.0", "spdy-transport": "^3.0.0",
@ -641,13 +641,13 @@
"sshpk": "^1.16.1", "sshpk": "^1.16.1",
"ssri": "^8.0.0", "ssri": "^8.0.0",
"stable": "^0.1.8", "stable": "^0.1.8",
"stack-utils": "^2.0.1", "stack-utils": "^2.0.2",
"static-extend": "^0.1.2", "static-extend": "^0.1.2",
"statuses": "^1.5.0", "statuses": "^2.0.0",
"std-env": "^2.2.1", "std-env": "^2.2.1",
"stream-browserify": "^2.0.2", "stream-browserify": "^3.0.0",
"stream-each": "^1.2.3", "stream-each": "^1.2.3",
"stream-http": "^3.1.0", "stream-http": "^3.1.1",
"stream-shift": "^1.0.1", "stream-shift": "^1.0.1",
"strict-uri-encode": "^2.0.0", "strict-uri-encode": "^2.0.0",
"string-width": "^4.2.0", "string-width": "^4.2.0",
@ -658,17 +658,17 @@
"strip-bom-string": "^1.0.0", "strip-bom-string": "^1.0.0",
"strip-eof": "^2.0.0", "strip-eof": "^2.0.0",
"stylehacks": "^4.0.3", "stylehacks": "^4.0.3",
"stylus": "^0.54.7", "stylus": "^0.54.8",
"stylus-loader": "^3.0.2", "stylus-loader": "^3.0.2",
"supports-color": "^7.1.0", "supports-color": "^7.1.0",
"svg-tags": "^1.0.0", "svg-tags": "^1.0.0",
"svgo": "^1.3.2", "svgo": "^1.3.2",
"tapable": "^1.1.3", "tapable": "^1.1.3",
"terser": "^4.6.10", "terser": "^5.0.0",
"terser-webpack-plugin": "^2.3.5", "terser-webpack-plugin": "^4.0.0",
"text-table": "^0.2.0", "text-table": "^0.2.0",
"through": "^2.3.8", "through": "^2.3.8",
"through2": "^3.0.1", "through2": "^4.0.2",
"thunky": "^1.1.0", "thunky": "^1.1.0",
"timers-browserify": "^2.0.11", "timers-browserify": "^2.0.11",
"timsort": "^0.3.0", "timsort": "^0.3.0",
@ -684,15 +684,15 @@
"toposort": "^2.0.2", "toposort": "^2.0.2",
"tough-cookie": "^4.0.0", "tough-cookie": "^4.0.0",
"tr46": "^2.0.2", "tr46": "^2.0.2",
"tslib": "^1.11.1", "tslib": "^2.0.0",
"tty-browserify": "^0.0.1", "tty-browserify": "^0.0.1",
"tunnel-agent": "^0.6.0", "tunnel-agent": "^0.6.0",
"tweetnacl": "^1.0.3", "tweetnacl": "^1.0.3",
"type-fest": "^0.13.0", "type-fest": "^0.16.0",
"type-is": "^1.6.18", "type-is": "^1.6.18",
"typedarray": "^0.0.6", "typedarray": "^0.0.6",
"uc.micro": "^1.0.6", "uc.micro": "^1.0.6",
"uglify-js": "^3.8.1", "uglify-js": "^3.10.1",
"unicode-canonical-property-names-ecmascript": "^1.0.4", "unicode-canonical-property-names-ecmascript": "^1.0.4",
"unicode-match-property-ecmascript": "^1.0.4", "unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.2.0", "unicode-match-property-value-ecmascript": "^1.2.0",
@ -702,7 +702,7 @@
"uniqs": "^2.0.0", "uniqs": "^2.0.0",
"unique-filename": "^1.1.1", "unique-filename": "^1.1.1",
"unique-slug": "^2.0.2", "unique-slug": "^2.0.2",
"universalify": "^1.0.0", "universalify": "^2.0.0",
"unpipe": "^1.0.0", "unpipe": "^1.0.0",
"unquote": "^1.1.1", "unquote": "^1.1.1",
"unset-value": "^1.0.0", "unset-value": "^1.0.0",
@ -711,60 +711,60 @@
"uri-js": "^4.2.2", "uri-js": "^4.2.2",
"urix": "^0.1.0", "urix": "^0.1.0",
"url": "^0.11.0", "url": "^0.11.0",
"url-loader": "^4.0.0", "url-loader": "^4.1.0",
"url-parse": "^1.4.7", "url-parse": "^1.4.7",
"use": "^3.1.1", "use": "^3.1.1",
"util": "^0.12.2", "util": "^0.12.3",
"util-deprecate": "^1.0.2", "util-deprecate": "^1.0.2",
"util.promisify": "^1.0.1", "util.promisify": "^1.0.1",
"utila": "^0.4.0", "utila": "^0.4.0",
"utils-merge": "^1.0.1", "utils-merge": "^1.0.1",
"uuid": "^7.0.3", "uuid": "^8.3.0",
"vary": "^1.1.2", "vary": "^1.1.2",
"vendors": "^1.0.4", "vendors": "^1.0.4",
"verror": "^1.10.0", "verror": "^1.10.0",
"vm-browserify": "^1.1.2", "vm-browserify": "^1.1.2",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-hot-reload-api": "^2.3.4", "vue-hot-reload-api": "^2.3.4",
"vue-loader": "^15.9.1", "vue-loader": "^15.9.3",
"vue-router": "^3.1.6", "vue-router": "^3.4.0",
"vue-server-renderer": "^2.6.11", "vue-server-renderer": "^2.6.11",
"vue-style-loader": "^4.1.2", "vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.6.11",
"vue-template-es2015-compiler": "^1.9.1", "vue-template-es2015-compiler": "^1.9.1",
"vuepress": "^1.4.0", "vuepress": "^1.5.3",
"vuepress-html-webpack-plugin": "^3.2.0", "vuepress-html-webpack-plugin": "^3.2.0",
"vuepress-plugin-container": "^2.1.2", "vuepress-plugin-container": "^2.1.4",
"vuepress-plugin-sitemap": "^2.3.1", "vuepress-plugin-sitemap": "^2.3.1",
"vuepress-plugin-smooth-scroll": "^0.0.9", "vuepress-plugin-smooth-scroll": "^0.0.9",
"vuepress-plugin-zooming": "^1.1.7", "vuepress-plugin-zooming": "^1.1.7",
"watchpack": "^1.6.1", "watchpack": "^1.7.4",
"wbuf": "^1.7.3", "wbuf": "^1.7.3",
"webidl-conversions": "^6.0.0", "webidl-conversions": "^6.1.0",
"webpack": "^4.42.1", "webpack": "^4.44.1",
"webpack-chain": "^6.4.0", "webpack-chain": "^6.5.1",
"webpack-dev-middleware": "^3.7.2", "webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.10.3", "webpack-dev-server": "^3.11.0",
"webpack-log": "^3.0.1", "webpack-log": "^3.0.1",
"webpack-merge": "^4.2.2", "webpack-merge": "^5.1.1",
"webpack-sources": "^1.4.3", "webpack-sources": "^1.4.3",
"webpackbar": "^4.0.0", "webpackbar": "^4.0.0",
"websocket-driver": "^0.7.3", "websocket-driver": "^0.7.4",
"websocket-extensions": "^0.1.3", "websocket-extensions": "^0.1.4",
"whatwg-url": "^8.0.0", "whatwg-url": "^8.1.0",
"when": "^3.7.8", "when": "^3.7.8",
"which": "^2.0.2", "which": "^2.0.2",
"which-module": "^2.0.0", "which-module": "^2.0.0",
"worker-farm": "^1.7.0", "worker-farm": "^1.7.0",
"wrap-ansi": "^6.2.0", "wrap-ansi": "^7.0.0",
"wrappy": "^1.0.2", "wrappy": "^1.0.2",
"ws": "^7.2.3", "ws": "^7.3.1",
"xmlbuilder": "^15.1.0", "xmlbuilder": "^15.1.1",
"xtend": "^4.0.2", "xtend": "^4.0.2",
"y18n": "^4.0.0", "y18n": "^4.0.0",
"yallist": "^4.0.0", "yallist": "^4.0.0",
"yargs": "^15.3.1", "yargs": "^15.4.1",
"yargs-parser": "^18.1.2", "yargs-parser": "^18.1.3",
"zepto": "^1.2.0" "zepto": "^1.2.0"
}, },
"devDependencies": {}, "devDependencies": {},

View File

@ -23,15 +23,31 @@ Here's an example configuration for `mysql` (or mariadb) that is compatible with
} }
``` ```
Alternatively if you would like to use a Sqlite database file:
```json
{
"database": {
"engine": "knex-native",
"knex": {
"client": "sqlite3",
"connection": {
"filename": "/data/database.sqlite"
}
}
}
}
```
Once you've created your configuration file it's easy to mount it in the docker container. Once you've created your configuration file it's easy to mount it in the docker container.
**Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys **Note:** After the first run of the application, the config file will be altered to include generated encryption keys unique to your installation. These keys
affect the login and session management of the application. If these keys change for any reason, all users will be logged out. affect the login and session management of the application. If these keys change for any reason, all users will be logged out.
### Database ### MySQL Database
This app doesn't come with a database, you have to provide one yourself. Currently only `mysql/mariadb` is supported for the minimum versions: If you opt for the MySQL configuration you will have to provide the database server yourself. You can also use MariaDB. Here are the minimum supported versions:
- MySQL v5.7.8+ - MySQL v5.7.8+
- MariaDB v10.2.7+ - MariaDB v10.2.7+

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@
<div class="col-sm-5 col-md-5"> <div class="col-sm-5 col-md-5">
<div class="form-group"> <div class="form-group">
<label class="form-label"><%- i18n('proxy-hosts', 'forward-host') %><span class="form-required">*</span></label> <label class="form-label"><%- i18n('proxy-hosts', 'forward-host') %><span class="form-required">*</span></label>
<input type="text" name="forward_host" class="form-control text-monospace model" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="50" required> <input type="text" name="forward_host" class="form-control text-monospace model" placeholder="" value="<%- forward_host %>" autocomplete="off" maxlength="200" required>
<span style="font-size: 9px;"><%- i18n('proxy-hosts', 'custom-forward-host-help') %></span> <span style="font-size: 9px;"><%- i18n('proxy-hosts', 'custom-forward-host-help') %></span>
</div> </div>
</div> </div>
@ -61,4 +61,4 @@
<i class="fa fa-trash"></i> <%- i18n('locations', 'delete') %> <i class="fa fa-trash"></i> <%- i18n('locations', 'delete') %>
</a> </a>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

3
test/.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode .vscode
node_modules node_modules
results
cypress/videos

View File

@ -1,4 +1,4 @@
FROM cypress/included:4.6.0 FROM cypress/included:4.12.1
COPY --chown=1000 ./test /test COPY --chown=1000 ./test /test

View File

@ -1,15 +1,12 @@
{ {
"requestTimeout": 30000, "requestTimeout": 30000,
"defaultCommandTimeout": 20000, "defaultCommandTimeout": 20000,
"reporter": "mocha-junit-reporter", "reporter": "cypress-multi-reporters",
"reporterOptions": { "reporterOptions": {
"jenkinsMode": true, "configFile": "multi-reporter.json"
"rootSuiteTitle": "Cypress",
"jenkinsClassnamePrefix": "Cypress.",
"mochaFile": "/results/junit/my-test-output-[hash].xml"
}, },
"videosFolder": "/results/videos", "videosFolder": "results/videos",
"screenshotsFolder": "/results/screenshots", "screenshotsFolder": "results/screenshots",
"env": { "env": {
"swaggerBase": "{{baseUrl}}/api/schema", "swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 4 "RETRIES": 4

View File

@ -1,13 +1,14 @@
{ {
"requestTimeout": 30000, "requestTimeout": 30000,
"defaultCommandTimeout": 20000, "defaultCommandTimeout": 20000,
"reporter": "junit", "reporter": "cypress-multi-reporters",
"reporterOptions": { "reporterOptions": {
"mochaFile": "results/junit/my-test-output-[hash].xml" "configFile": "multi-reporter.json"
}, },
"video": false, "videos": false,
"screenshotsFolder": "cypress/results/screenshots", "screenshotsFolder": "results/screenshots",
"env": { "env": {
"swaggerBase": "{{baseUrl}}/api/schema" "swaggerBase": "{{baseUrl}}/api/schema",
"RETRIES": 0
} }
} }

View File

@ -2,17 +2,15 @@
describe('Basic API checks', () => { describe('Basic API checks', () => {
it('Should return a valid health payload', function () { it('Should return a valid health payload', function () {
cy.wait(2000);
cy.task('backendApiGet', { cy.task('backendApiGet', {
path: '/api/', path: '/api/',
}).then((data) => { }).then((data) => {
// Check the swagger schema: // Check the swagger schema:
cy.validateSwaggerSchema('get', '/', data); cy.validateSwaggerSchema('get', 200, '/', data);
}); });
}); });
it('Should return a valid schema payload', function () { it('Should return a valid schema payload', function () {
cy.wait(2000);
cy.task('backendApiGet', { cy.task('backendApiGet', {
path: '/api/schema', path: '/api/schema',
}).then((data) => { }).then((data) => {

View File

@ -0,0 +1,48 @@
/// <reference types="Cypress" />
describe('Users endpoints', () => {
let token;
before(() => {
cy.getToken().then((tok) => {
token = tok;
});
});
it('Should be able to get yourself', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users/me'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
});
});
it('Should be able to get all users', function() {
cy.task('backendApiGet', {
token: token,
path: '/api/users'
}).then((data) => {
cy.validateSwaggerSchema('get', 200, '/users', data);
expect(data.length).to.be.greaterThan(0);
});
});
it('Should be able to update yourself', function() {
cy.task('backendApiPut', {
token: token,
path: '/api/users/me',
data: {
name: 'changed name'
}
}).then((data) => {
cy.validateSwaggerSchema('put', 200, '/users/{userID}', data);
expect(data).to.have.property('id');
expect(data.id).to.be.greaterThan(0);
expect(data.name).to.be.equal('changed name');
});
});
});

View File

@ -13,82 +13,30 @@
* Check the swagger schema: * Check the swagger schema:
* *
* @param {string} method API Method in swagger doc, "get", "put", "post", "delete" * @param {string} method API Method in swagger doc, "get", "put", "post", "delete"
* @param {number} statusCode API status code in swagger doc
* @param {string} path Swagger doc endpoint path, exactly as defined in swagger doc * @param {string} path Swagger doc endpoint path, exactly as defined in swagger doc
* @param {*} data The API response data to check against the swagger schema * @param {*} data The API response data to check against the swagger schema
*/ */
Cypress.Commands.add('validateSwaggerSchema', (method, path, data) => { Cypress.Commands.add('validateSwaggerSchema', (method, statusCode, path, data) => {
cy.task('validateSwaggerSchema', { cy.task('validateSwaggerSchema', {
file: Cypress.env('swaggerBase'), file: Cypress.env('swaggerBase'),
endpoint: path, endpoint: path,
method: method, method: method,
statusCode: 200, statusCode: statusCode,
responseSchema: data, responseSchema: data,
verbose: true verbose: true
}).should('equal', null); }).should('equal', null);
}); });
Cypress.Commands.add('getToken', () => { Cypress.Commands.add('getToken', () => {
cy.task('backendApiGet', { // login with existing user
path: '/api/', cy.task('backendApiPost', {
}).then((data) => { path: '/api/tokens',
// Check the swagger schema:
cy.task('validateSwaggerSchema', {
endpoint: '/',
method: 'get',
statusCode: 200,
responseSchema: data,
verbose: true,
}).should('equal', null);
if (!data.result.setup) {
cy.log('Setup = false');
// create a new user
cy.createInitialUser().then(() => {
return cy.getToken();
});
} else {
cy.log('Setup = true');
// login with existing user
cy.task('backendApiPost', {
path: '/api/tokens',
data: {
type: 'password',
identity: 'jc@jc21.com',
secret: 'changeme'
}
}).then(res => {
cy.wrap(res.result.token);
});
}
});
});
Cypress.Commands.add('createInitialUser', () => {
return cy.task('backendApiPost', {
path: '/api/users',
data: { data: {
name: 'Jamie Curnow', identity: 'admin@example.com',
nickname: 'James', secret: 'changeme'
email: 'jc@jc21.com',
roles: [],
is_disabled: false,
auth: {
type: 'password',
secret: 'changeme'
}
} }
}).then((data) => { }).then(res => {
// Check the swagger schema: cy.wrap(res.token);
cy.task('validateSwaggerSchema', {
endpoint: '/users',
method: 'post',
statusCode: 201,
responseSchema: data,
verbose: true
}).should('equal', null);
expect(data.result).to.have.property('id');
expect(data.result.id).to.be.greaterThan(0);
cy.wrap(data.result);
}); });
}); });

9
test/multi-reporter.json Normal file
View File

@ -0,0 +1,9 @@
{
"reporterEnabled": "spec, mocha-junit-reporter",
"mochaJunitReporterReporterOptions": {
"jenkinsMode": true,
"rootSuiteTitle": "Cypress.npm",
"jenkinsClassnamePrefix": "Cypress.npm.",
"mochaFile": "results/junit/cypress.npm.[hash].xml"
}
}

View File

@ -4,21 +4,23 @@
"description": "", "description": "",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@jc21/cypress-swagger-validation": "^0.0.5", "@jc21/cypress-swagger-validation": "^0.0.9",
"@jc21/restler": "^3.4.0", "@jc21/restler": "^3.4.0",
"chalk": "^3.0.0", "chalk": "^4.1.0",
"cypress": "^4.6.0", "cypress": "^4.12.1",
"cypress-multi-reporters": "^1.4.0",
"cypress-plugin-retries": "^1.5.2", "cypress-plugin-retries": "^1.5.2",
"eslint": "^6.7.2", "eslint": "^7.6.0",
"eslint-plugin-align-assignments": "^1.1.2", "eslint-plugin-align-assignments": "^1.1.2",
"eslint-plugin-chai-friendly": "^0.5.0", "eslint-plugin-chai-friendly": "^0.6.0",
"eslint-plugin-cypress": "^2.8.0", "eslint-plugin-cypress": "^2.11.1",
"lodash": "^4.17.15", "lodash": "^4.17.19",
"mocha": "^6.2.2", "mocha": "^8.1.1",
"mocha-junit-reporter": "^1.23.1" "mocha-junit-reporter": "^2.0.0"
}, },
"scripts": { "scripts": {
"cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=http://127.0.0.1:3081" "cypress": "cypress open --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}",
"cypress:headless": "cypress run --config-file=cypress/config/dev.json --config baseUrl=${BASE_URL:-http://127.0.0.1:3081}"
}, },
"author": "", "author": "",
"license": "ISC" "license": "ISC"

File diff suppressed because it is too large Load Diff