Database migration and seeding
This commit is contained in:
parent
25c5a06ec3
commit
44e6fd31d2
|
@ -0,0 +1,21 @@
|
|||
require('dotenv').config();
|
||||
|
||||
module.exports = {
|
||||
client: process.env.DB_CLIENT,
|
||||
connection: {
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_DATABASE
|
||||
},
|
||||
pool: {
|
||||
min: process.env.DATABASE_POOL_MIN || 2,
|
||||
max: process.env.DATABASE_POOL_MAX || 10
|
||||
},
|
||||
migrations: {
|
||||
directory: 'src/api/database/migrations'
|
||||
},
|
||||
seeds: {
|
||||
directory: 'src/api/database/seeds'
|
||||
}
|
||||
};
|
11
package.json
11
package.json
|
@ -10,11 +10,14 @@
|
|||
},
|
||||
"main": "src/_scripts/start.js",
|
||||
"scripts": {
|
||||
"setup": "node src/wizard.js",
|
||||
"api": "node src/api/structures/Server",
|
||||
"site": "nuxt",
|
||||
"setup": "yarn build && node src/wizard.js",
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
"start": "cross-env NODE_ENV=production node src/start && nuxt start"
|
||||
"migrate": "yarn knex migrate:latest",
|
||||
"seed": "yarn knex seed:run",
|
||||
"api": "node src/api/structures/Server",
|
||||
"site": "cross-env NODE_ENV=production nuxt start",
|
||||
"update": "git pull && yarn migrate && yarn build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
exports.up = async knex => {
|
||||
await knex.schema.createTable('users', table => {
|
||||
table.increments();
|
||||
table.string('username');
|
||||
table.string('password');
|
||||
table.boolean('enabled').defaultTo(true);
|
||||
table.boolean('isAdmin').defaultTo(false);
|
||||
table.string('apiKey');
|
||||
table.timestamp('passwordEditedAt');
|
||||
table.timestamp('apiKeyEditedAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('albums', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.string('name');
|
||||
table.timestamp('zippedAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('files', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.string('name');
|
||||
table.string('original');
|
||||
table.string('type');
|
||||
table.integer('size');
|
||||
table.string('hash');
|
||||
table.string('ip');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('links', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.integer('albumId');
|
||||
table.string('identifier');
|
||||
table.integer('views').defaultTo(0);
|
||||
table.boolean('enabled').defaultTo(true);
|
||||
table.boolean('enableDownload').defaultTo(true);
|
||||
table.timestamp('expiresAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('albumsFiles', table => {
|
||||
table.increments();
|
||||
table.integer('albumId');
|
||||
table.integer('fileId');
|
||||
});
|
||||
|
||||
await knex.schema.createTable('albumsLinks', table => {
|
||||
table.increments();
|
||||
table.integer('albumId');
|
||||
table.integer('linkId');
|
||||
});
|
||||
};
|
||||
exports.down = async knex => {
|
||||
await knex.schema.dropTableIfExists('users');
|
||||
await knex.schema.dropTableIfExists('albums');
|
||||
await knex.schema.dropTableIfExists('files');
|
||||
await knex.schema.dropTableIfExists('links');
|
||||
await knex.schema.dropTableIfExists('albumsFiles');
|
||||
await knex.schema.dropTableIfExists('albumsLinks');
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
const bcrypt = require('bcrypt');
|
||||
const moment = require('moment');
|
||||
const randomstring = require('randomstring');
|
||||
|
||||
exports.seed = async db => {
|
||||
const now = moment.utc().toDate();
|
||||
const user = await db.table('users').where({ username: 'root' }).first();
|
||||
if (user) return;
|
||||
try {
|
||||
const hash = await bcrypt.hash(process.env.ADMIN_PASSWORD, 10);
|
||||
await db.table('users').insert({
|
||||
username: process.env.ADMIN_ACCOUNT,
|
||||
password: hash,
|
||||
apiKey: randomstring.generate(64),
|
||||
passwordEditedAt: now,
|
||||
apiKeyEditedAt: now,
|
||||
createdAt: now,
|
||||
editedAt: now,
|
||||
isAdmin: true
|
||||
});
|
||||
console.log();
|
||||
console.log('====================================================');
|
||||
console.log('== Successfully created the admin account. ==');
|
||||
console.log('====================================================');
|
||||
console.log('== Run `yarn api` and `yarn site` next ==');
|
||||
console.log('== preferably with pm2 or tmux to keep them alive ==');
|
||||
console.log('====================================================');
|
||||
console.log();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
const log = require('../utils/Log');
|
||||
const { server } = require('../../../config');
|
||||
const db = require('knex')(server.database);
|
||||
const bcrypt = require('bcrypt');
|
||||
const moment = require('moment');
|
||||
const randomstring = require('randomstring');
|
||||
|
||||
class Database {
|
||||
constructor() {
|
||||
this.createTables();
|
||||
}
|
||||
|
||||
async createTables() {
|
||||
if (!await db.schema.hasTable('users')) {
|
||||
await db.schema.createTable('users', table => {
|
||||
table.increments();
|
||||
table.string('username');
|
||||
table.string('password');
|
||||
table.boolean('enabled').defaultTo(true);
|
||||
table.boolean('isAdmin').defaultTo(false);
|
||||
table.string('apiKey');
|
||||
table.timestamp('passwordEditedAt');
|
||||
table.timestamp('apiKeyEditedAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
}
|
||||
|
||||
if (!await db.schema.hasTable('albums')) {
|
||||
await db.schema.createTable('albums', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.string('name');
|
||||
// table.string('identifier');
|
||||
// table.boolean('enabled');
|
||||
// table.boolean('enableDownload').defaultTo(true);
|
||||
table.timestamp('zippedAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
}
|
||||
|
||||
if (!await db.schema.hasTable('files')) {
|
||||
await db.schema.createTable('files', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.string('name');
|
||||
table.string('original');
|
||||
table.string('type');
|
||||
table.integer('size');
|
||||
table.string('hash');
|
||||
table.string('ip');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
}
|
||||
|
||||
if (!await db.schema.hasTable('links')) {
|
||||
await db.schema.createTable('links', table => {
|
||||
table.increments();
|
||||
table.integer('userId');
|
||||
table.integer('albumId');
|
||||
table.string('identifier');
|
||||
table.integer('views').defaultTo(0);
|
||||
table.boolean('enabled').defaultTo(true);
|
||||
table.boolean('enableDownload').defaultTo(true);
|
||||
table.timestamp('expiresAt');
|
||||
table.timestamp('createdAt');
|
||||
table.timestamp('editedAt');
|
||||
});
|
||||
}
|
||||
|
||||
if (!await db.schema.hasTable('albumsFiles')) {
|
||||
await db.schema.createTable('albumsFiles', table => {
|
||||
table.increments();
|
||||
table.integer('albumId');
|
||||
table.integer('fileId');
|
||||
});
|
||||
}
|
||||
|
||||
if (!await db.schema.hasTable('albumsLinks')) {
|
||||
await db.schema.createTable('albumsLinks', table => {
|
||||
table.increments();
|
||||
table.integer('albumId');
|
||||
table.integer('linkId');
|
||||
});
|
||||
}
|
||||
|
||||
const now = moment.utc().toDate();
|
||||
const user = await db.table('users').where({ username: 'root' }).first();
|
||||
if (user) return;
|
||||
try {
|
||||
const hash = await bcrypt.hash('root', 10);
|
||||
await db.table('users').insert({
|
||||
username: 'root',
|
||||
password: hash,
|
||||
apiKey: randomstring.generate(64),
|
||||
passwordEditedAt: now,
|
||||
apiKeyEditedAt: now,
|
||||
createdAt: now,
|
||||
editedAt: now,
|
||||
isAdmin: true
|
||||
});
|
||||
log.success('Successfully created the root user with password "root". Make sure to log in and change it!');
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
if (error) log.error('Error generating password hash for root');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Database;
|
|
@ -8,7 +8,6 @@ const RateLimit = require('express-rate-limit');
|
|||
const bodyParser = require('body-parser');
|
||||
const jetpack = require('fs-jetpack');
|
||||
const path = require('path');
|
||||
const Database = require('./Database');
|
||||
|
||||
const rateLimiter = new RateLimit({
|
||||
windowMs: process.env.RATE_LIMIT_WINDOW,
|
||||
|
@ -35,7 +34,6 @@ class Server {
|
|||
this.server.use(bodyParser.json());
|
||||
// this.server.use(rateLimiter);
|
||||
this.routesFolder = path.join(__dirname, '..', 'routes');
|
||||
this.database = new Database();
|
||||
}
|
||||
|
||||
registerAllTheRoutes() {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const randomstring = require('randomstring');
|
||||
const jetpack = require('fs-jetpack');
|
||||
const qoa = require('qoa');
|
||||
qoa.config({
|
||||
|
@ -15,6 +16,10 @@ async function start() {
|
|||
});
|
||||
if (!confirm.run) process.exit(0);
|
||||
|
||||
console.log();
|
||||
console.log('You can manually edit .env file after the wizard to edit values');
|
||||
console.log();
|
||||
|
||||
const wizard = [
|
||||
{
|
||||
type: 'input',
|
||||
|
@ -93,10 +98,35 @@ async function start() {
|
|||
accept: 'y',
|
||||
deny: 'n'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
query: 'Name of the admin account?',
|
||||
handle: 'ADMIN_ACCOUNT'
|
||||
},
|
||||
{
|
||||
type: 'secure',
|
||||
query: 'Type a secure password for the root user:',
|
||||
handle: 'ROOT_PASSWORD'
|
||||
handle: 'ADMIN_PASSWORD'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
query: 'Database host',
|
||||
handle: 'DB_HOST'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
query: 'Database user',
|
||||
handle: 'DB_USER'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
query: 'Database password',
|
||||
handle: 'DB_PASSWORD'
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
query: 'Database name',
|
||||
handle: 'DB_DATABASE'
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -109,13 +139,9 @@ async function start() {
|
|||
RATE_LIMIT_WINDOW: 2,
|
||||
RATE_LIMIT_MAX: 5,
|
||||
DB_CLIENT: 'pg',
|
||||
DB_HOST: 'localhost',
|
||||
DB_USER: '',
|
||||
DB_PASSWORD: '',
|
||||
DB_DATABASE: '',
|
||||
BLOCKED_EXTENSIONS: ['.jar', '.exe', '.msi', '.com', '.bat', '.cmd', '.scr', '.ps1', '.sh'],
|
||||
UPLOAD_FOLDER: 'uploads',
|
||||
SECRET: 'SuperSecretPassphraseHere',
|
||||
SECRET: randomstring.generate(64),
|
||||
MAX_LINKS_PER_ALBUM: 5
|
||||
};
|
||||
|
||||
|
@ -128,7 +154,11 @@ async function start() {
|
|||
jetpack.write('.env', envfile);
|
||||
|
||||
console.log();
|
||||
console.log('== .env file generated successfully. You can now run lolisafe ==');
|
||||
console.log('=============================================');
|
||||
console.log('== .env file generated successfully. ==');
|
||||
console.log('=============================================');
|
||||
console.log('== Run `yarn migrate` and `yarn seed` next ==');
|
||||
console.log('=============================================');
|
||||
console.log();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue