Move api into api subdirectory

This commit is contained in:
rijkvanzanten
2020-07-29 11:22:56 -04:00
parent 565fbdb212
commit bde7069cce
117 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
import fse from 'fs-extra';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { resolve } from 'path';
import { databaseQuestions } from './questions';
import { drivers, getDriverForClient } from '../../utils/drivers';
import createEnv from '../../utils/create-env';
import execa from 'execa';
import path from 'path';
import { v4 as uuidV4 } from 'uuid';
import ora from 'ora';
import argon2 from 'argon2';
import runSeed from '../../../database/run-seed';
import createDBConnection, { Credentials } from '../../utils/create-db-connection';
export default async function create(directory: string, options: Record<string, any>) {
const rootPath = resolve(directory);
checkRequirements();
if (await fse.pathExists(rootPath)) {
const stat = await fse.stat(rootPath);
if (stat.isDirectory() === false) {
console.error(
`Destination '${chalk.red(directory)}' already exists and is not a directory.`
);
process.exit(1);
}
const files = await fse.readdir(rootPath);
if (files.length > 0) {
console.error(
`Destination '${chalk.red(
directory
)}' already exists and is not an empty directory.`
);
process.exit(1);
}
}
await fse.mkdir(rootPath);
await fse.mkdir(path.join(rootPath, 'uploads'));
await fse.mkdir(path.join(rootPath, 'extensions'));
console.log('Adding package.json');
await execa('npm', ['init', '-y'], {
cwd: rootPath,
stdin: 'ignore',
});
const spinner = ora('Installing Directus').start();
await execa('npm', ['install', 'directus', '--production', '--no-optional'], {
cwd: rootPath,
stdin: 'ignore',
});
spinner.stopAndPersist();
let { client } = await inquirer.prompt([
{
type: 'list',
name: 'client',
message: 'Choose your database client',
choices: Object.values(drivers),
},
]);
const dbClient = getDriverForClient(client)!;
const credentials: Credentials = await inquirer.prompt(
(databaseQuestions[dbClient] as any[]).map((question: Function) =>
question({ client: dbClient, filepath: rootPath })
)
);
console.log(`Installing database...`);
const db = createDBConnection(dbClient, credentials);
await runSeed(db, 'system');
console.log(`Creating the .env file...`);
await createEnv(dbClient, credentials, rootPath);
console.log(`Create your first admin user:`);
const firstUser = await inquirer.prompt([
{
type: 'input',
name: 'email',
message: 'Email',
default: 'admin@example.com',
},
{
type: 'password',
name: 'password',
message: 'Password',
mask: '*',
},
]);
firstUser.password = await argon2.hash(firstUser.password);
const userID = uuidV4();
const roleID = uuidV4();
await db('directus_roles').insert({
id: roleID,
name: 'Admin',
icon: 'verified_user',
admin: true,
});
await db('directus_users').insert({
id: userID,
status: 'active',
email: firstUser.email,
password: firstUser.password,
first_name: 'Admin',
last_name: 'User',
role: roleID,
});
db.destroy();
console.log(`
Your project has been created at ${chalk.green(rootPath)}.
Start Directus by running:
${chalk.blue('cd')} ${rootPath}
${chalk.blue('npx directus')} start
`);
}
function checkRequirements() {
const nodeVersion = process.versions.node;
const major = +nodeVersion.split('.')[0];
if (major < 10) {
console.error(`You are running Node ${nodeVersion}.`);
console.error('Directus requires Node 10 and up.');
console.error('Please update your Node version and try again.');
process.exit(1);
}
}

View File

@@ -0,0 +1,59 @@
import path from 'path';
const filename = ({ filepath }: { filepath: string }) => ({
type: 'input',
name: 'filename',
message: 'Database File Path:',
default: path.join(filepath, 'data.db'),
});
const host = () => ({
type: 'input',
name: 'host',
message: 'Database Host:',
default: '127.0.0.1',
});
const port = ({ client }: { client: string }) => ({
type: 'input',
name: 'port',
message: 'Port:',
default() {
const ports: Record<string, number> = {
pg: 5432,
mysql: 3306,
oracledb: 1521,
mssql: 1433,
};
return ports[client];
},
});
const database = () => ({
type: 'input',
name: 'database',
message: 'Database Name:',
default: 'directus',
});
const user = () => ({
type: 'input',
name: 'user',
message: 'Database User:',
});
const password = () => ({
type: 'password',
name: 'password',
message: 'Database Password:',
mask: '*',
});
export const databaseQuestions = {
sqlite3: [filename],
mysql: [host, port, database, user, password],
pg: [host, port, database, user, password],
oracledb: [host, port, database, user, password],
mssql: [host, port, database, user, password],
};

View File

@@ -0,0 +1,14 @@
import logger from '../../logger';
import getPort from 'get-port';
import dotenv from 'dotenv';
export default async function start() {
dotenv.config();
const app = require('../../app').default;
const port = process.env.PORT || (await getPort({ port: 3000 }));
app.listen(port, () => {
logger.info(`Server started at port ${port}`);
});
}

17
api/src/cli/index.ts Normal file
View File

@@ -0,0 +1,17 @@
#!/usr/bin/env node
import program from 'commander';
const pkg = require('../../package.json');
import start from './commands/start';
import create from './commands/create';
program.version(pkg.version, '-v, --version');
program.name('directus').usage('[command] [options]');
program.command('create <directory>').description('Create a new Directus Project').action(create);
program.command('start').description('Start the Directus API').action(start);
program.parseAsync(process.argv);

View File

@@ -0,0 +1,51 @@
import knex, { Config } from 'knex';
import path from 'path';
export type Credentials = {
filename?: string;
host?: string;
port?: number;
database?: string;
user?: string;
password?: string;
};
export default function createDBConnection(
client: 'sqlite3' | 'mysql' | 'pg' | 'oracledb' | 'mssql',
credentials: Credentials
) {
let connection: Config['connection'] = {};
if (client === 'sqlite3') {
const { filename } = credentials;
connection = {
filename: filename as string,
};
} else {
const { host, port, database, user, password } = credentials as Credentials;
connection = {
host: host,
port: port,
database: database,
user: user,
password: password,
};
}
const knexConfig: Config = {
client: client,
connection: connection,
seeds: {
extension: 'js',
directory: path.resolve(__dirname, '../../database/seeds/'),
},
};
if (client === 'sqlite3') {
knexConfig.useNullAsDefault = true;
}
const db = knex(knexConfig);
return db;
}

View File

@@ -0,0 +1,34 @@
####################################################################################################
# General
{{ general }}
####################################################################################################
# Database
{{ database }}
####################################################################################################
# File Storage
{{ storage }}
####################################################################################################
# Security
{{ security }}
####################################################################################################
# SSO (OAuth) Providers
{{ oauth }}
####################################################################################################
# Extensions
{{ extensions }}
####################################################################################################
# Email
{{ email }}

View File

@@ -0,0 +1,79 @@
import { drivers } from '../drivers';
import { Credentials } from '../create-db-connection';
import { v4 as uuidv4 } from 'uuid';
import { nanoid } from 'nanoid';
import { Liquid } from 'liquidjs';
import fs from 'fs';
import { promisify } from 'util';
import path from 'path';
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const liquidEngine = new Liquid({
extname: '.liquid',
});
const defaults = {
general: {
PORT: 3000,
PUBLIC_URL: '/',
},
storage: {
STORAGE_LOCATIONS: 'local',
STORAGE_LOCAL_PUBLIC_URL: '/uploads',
STORAGE_LOCAL_DRIVER: 'local',
STORAGE_LOCAL_ROOT: './uploads',
},
security: {
UUID: uuidv4(),
SECRET: nanoid(32),
ACCESS_TOKEN_TTL: '15m',
REFRESH_TOKEN_TTL: '7d',
REFRESH_TOKEN_COOKIE_SECURE: false,
REFRESH_TOKEN_COOKIE_SAME_SITE: 'lax',
},
oauth: {
OAUTH_PROVIDERS: '',
},
extensions: {
EXTENSIONS_PATH: './extensions',
},
email: {
EMAIL_FROM: 'no-reply@directus.io',
EMAIL_TRANSPORT: 'sendmail',
EMAIL_SENDMAIL_NEW_LINE: 'unix',
EMAIL_SENDMAIL_PATH: '/usr/sbin/sendmail',
},
};
export default async function createEnv(
client: keyof typeof drivers,
credentials: Credentials,
directory: string
) {
const config: Record<string, any> = {
...defaults,
database: {
DB_CLIENT: client,
},
};
for (const [key, value] of Object.entries(credentials)) {
config.database[`DB_${key.toUpperCase()}`] = value;
}
const configAsStrings: any = {};
for (const [key, value] of Object.entries(config)) {
configAsStrings[key] = '';
for (const [envKey, envValue] of Object.entries(value)) {
configAsStrings[key] += `${envKey}="${envValue}"\n`;
}
}
const templateString = await readFile(path.join(__dirname, 'env-stub.liquid'), 'utf8');
const text = await liquidEngine.parseAndRender(templateString, configAsStrings);
await writeFile(path.join(directory, '.env'), text);
}

View File

@@ -0,0 +1,15 @@
export const drivers = {
sqlite3: 'SQLite',
mysql: 'MySQL (/ MariaDB / Aurora)',
pg: 'PostgreSQL (/ Amazon Redshift)',
oracledb: 'Oracle Database',
mssql: 'Microsoft SQL Server',
};
export function getDriverForClient(client: string): keyof typeof drivers | null {
for (const [key, value] of Object.entries(drivers)) {
if (value === client) return key as keyof typeof drivers;
}
return null;
}