New dev commands and updates
This commit is contained in:
parent
a6f8b0b2c9
commit
c33c7f04d8
|
@ -1,14 +1,15 @@
|
||||||
# Copy this file to .env, remove this comment and change the keys
|
# Copy this file to .env, remove this comment and change the keys
|
||||||
#
|
#
|
||||||
# Please use `openssl rand -hex 32` to create SEQUELIZE_SECRET
|
# Please use `openssl rand -hex 32` to create SECRET_KEY
|
||||||
|
|
||||||
DATABASE_URL=postgres://user:pass@example.com:5432/outline
|
DATABASE_URL=postgres://user:pass@example.com:5432/outline
|
||||||
DATABASE_URL_TEST=postgres://user:pass@example.com:5432/outline-test
|
DATABASE_URL_TEST=postgres://user:pass@example.com:5432/outline-test
|
||||||
|
SECRET_KEY=F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
|
||||||
PORT=3000
|
PORT=3000
|
||||||
REDIS_URL=redis://localhost:6379
|
REDIS_URL=redis://localhost:6379
|
||||||
SEQUELIZE_SECRET=F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
|
|
||||||
SLACK_KEY=71315967491.XXXXXXXXXX
|
SLACK_KEY=71315967491.XXXXXXXXXX
|
||||||
SLACK_SECRET=d2dc414f9953226bad0a356c794XXXXX
|
SLACK_SECRET=d2dc414f9953226bad0a356c794XXXXX
|
||||||
URL=http://localhost:3000
|
URL=http://localhost:3000
|
||||||
DEPLOYMENT=hosted
|
DEPLOYMENT=hosted
|
||||||
|
ENABLE_UPDATES=true
|
||||||
GOOGLE_ANALYTICS_ID=
|
GOOGLE_ANALYTICS_ID=
|
||||||
|
|
22
README.md
22
README.md
|
@ -20,8 +20,28 @@ To install and run the application:
|
||||||
1. Register a Slack app at https://api.slack.com/apps
|
1. Register a Slack app at https://api.slack.com/apps
|
||||||
1. Copy the file `.env.sample` to `.env` and fill out the keys
|
1. Copy the file `.env.sample` to `.env` and fill out the keys
|
||||||
1. Run DB migrations `yarn sequelize db:migrate`
|
1. Run DB migrations `yarn sequelize db:migrate`
|
||||||
1. Start the development server `yarn start`
|
|
||||||
|
To run Outline in development mode with server and frontend code reloading:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
To run Outline in production mode:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
yarn start
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Server
|
||||||
|
|
||||||
|
To enable debugging statements, set the following env vars:
|
||||||
|
|
||||||
|
```
|
||||||
|
DEBUG=sql,cache,presenters
|
||||||
|
```
|
||||||
|
|
||||||
## Migrations
|
## Migrations
|
||||||
|
|
||||||
|
|
9
app.json
9
app.json
|
@ -28,7 +28,7 @@
|
||||||
"REDIS_URL": {
|
"REDIS_URL": {
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"SEQUELIZE_SECRET": {
|
"SECRET_KEY": {
|
||||||
"required": true
|
"required": true
|
||||||
},
|
},
|
||||||
"SLACK_KEY": {
|
"SLACK_KEY": {
|
||||||
|
@ -51,10 +51,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"formation": {},
|
"formation": {},
|
||||||
"addons": ["heroku-postgresql", "heroku-redis"],
|
"addons": [
|
||||||
|
"heroku-postgresql",
|
||||||
|
"heroku-redis"
|
||||||
|
],
|
||||||
"buildpacks": [
|
"buildpacks": [
|
||||||
{
|
{
|
||||||
"url": "heroku/nodejs"
|
"url": "heroku/nodejs"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ machine:
|
||||||
environment:
|
environment:
|
||||||
ENVIRONMENT: test
|
ENVIRONMENT: test
|
||||||
PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin"
|
PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin"
|
||||||
SEQUELIZE_SECRET: F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
|
SECRET_KEY: F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B
|
||||||
DATABASE_URL_TEST: postgres://ubuntu@localhost:5432/circle_test
|
DATABASE_URL_TEST: postgres://ubuntu@localhost:5432/circle_test
|
||||||
DATABASE_URL: postgres://ubuntu@localhost:5432/circle_test
|
DATABASE_URL: postgres://ubuntu@localhost:5432/circle_test
|
||||||
|
|
||||||
|
|
|
@ -6,3 +6,8 @@ declare var BASE_URL: string;
|
||||||
declare var BUGSNAG_KEY: ?string;
|
declare var BUGSNAG_KEY: ?string;
|
||||||
declare var DEPLOYMENT: string;
|
declare var DEPLOYMENT: string;
|
||||||
declare var Bugsnag: any;
|
declare var Bugsnag: any;
|
||||||
|
declare var process: {
|
||||||
|
env: {
|
||||||
|
[string]: string,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
25
index.js
25
index.js
|
@ -1,7 +1,30 @@
|
||||||
require('./init');
|
require('./init');
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
console.log(
|
||||||
|
'\n\x1b[33m%s\x1b[0m',
|
||||||
|
'Running Outline in production mode. Use `yarn dev` to run in development with live code reloading'
|
||||||
|
);
|
||||||
|
} else if (process.env.NODE_ENV === 'development') {
|
||||||
|
console.log(
|
||||||
|
'\n\x1b[33m%s\x1b[0m',
|
||||||
|
'Running Outline in development mode with React hot reloading. To run Outline in production mode, use `yarn start`'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const app = require('./server').default;
|
const app = require('./server').default;
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
|
|
||||||
|
if (
|
||||||
|
process.env.SECRET_KEY ===
|
||||||
|
'F0E5AD933D7F6FD8F4DBB3E038C501C052DC0593C686D21ACB30AE205D2F634B'
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
'Please set SECRET_KEY env variable with output of `openssl rand -hex 32`'
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
const server = http.createServer(app.callback());
|
const server = http.createServer(app.callback());
|
||||||
server.listen(process.env.PORT || '3000');
|
server.listen(process.env.PORT || '3000');
|
||||||
server.on('error', err => {
|
server.on('error', err => {
|
||||||
|
@ -9,5 +32,5 @@ server.on('error', err => {
|
||||||
});
|
});
|
||||||
server.on('listening', () => {
|
server.on('listening', () => {
|
||||||
const address = server.address();
|
const address = server.address();
|
||||||
console.log(`Listening on http://localhost:${address.port}`);
|
console.log(`\n> Listening on http://localhost:${address.port}\n`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
"build:analyze":
|
"build:analyze":
|
||||||
"NODE_ENV=production webpack --config webpack.config.prod.js --json | webpack-bundle-size-analyzer",
|
"NODE_ENV=production webpack --config webpack.config.prod.js --json | webpack-bundle-size-analyzer",
|
||||||
"build": "npm run clean && npm run build:webpack",
|
"build": "npm run clean && npm run build:webpack",
|
||||||
"start": "node index.js",
|
"start": "NODE_ENV=production node index.js",
|
||||||
"dev":
|
"dev": "NODE_ENV=development nodemon --inspect --watch server index.js",
|
||||||
"NODE_ENV=development DEBUG=sql,cache,presenters ./node_modules/.bin/nodemon --inspect --watch server index.js",
|
|
||||||
"lint": "npm run lint:flow && npm run lint:js",
|
"lint": "npm run lint:flow && npm run lint:js",
|
||||||
"lint:js": "eslint app",
|
"lint:js": "eslint app",
|
||||||
"lint:flow": "flow",
|
"lint:flow": "flow",
|
||||||
|
|
|
@ -5,6 +5,7 @@ import logger from 'koa-logger';
|
||||||
import mount from 'koa-mount';
|
import mount from 'koa-mount';
|
||||||
import Koa from 'koa';
|
import Koa from 'koa';
|
||||||
import bugsnag from 'bugsnag';
|
import bugsnag from 'bugsnag';
|
||||||
|
import updates from './utils/updates';
|
||||||
|
|
||||||
import api from './api';
|
import api from './api';
|
||||||
import routes from './routes';
|
import routes from './routes';
|
||||||
|
@ -82,4 +83,17 @@ app.use(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Production updates and anonymous analytics.
|
||||||
|
*
|
||||||
|
* Set ENABLE_UPDATES=false to disable them for your installation
|
||||||
|
*/
|
||||||
|
if (
|
||||||
|
process.env.ENABLE_UPDATES !== 'false' &&
|
||||||
|
process.env.NODE_ENV === 'production'
|
||||||
|
) {
|
||||||
|
updates();
|
||||||
|
setInterval(updates, 24 * 3600 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
export default app;
|
export default app;
|
||||||
|
|
|
@ -3,7 +3,7 @@ import Sequelize from 'sequelize';
|
||||||
import EncryptedField from 'sequelize-encrypted';
|
import EncryptedField from 'sequelize-encrypted';
|
||||||
import debug from 'debug';
|
import debug from 'debug';
|
||||||
|
|
||||||
const secretKey = process.env.SEQUELIZE_SECRET;
|
const secretKey = process.env.SECRET_KEY;
|
||||||
|
|
||||||
export const encryptedFields = EncryptedField(Sequelize, secretKey);
|
export const encryptedFields = EncryptedField(Sequelize, secretKey);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
// @flow
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import invariant from 'invariant';
|
||||||
|
import fetch from 'isomorphic-fetch';
|
||||||
|
import { client } from '../redis';
|
||||||
|
import packageInfo from '../../package.json';
|
||||||
|
|
||||||
|
import { User, Team, Collection, Document } from '../models';
|
||||||
|
|
||||||
|
const UPDATES_URL = 'https://updates.getoutline.com';
|
||||||
|
const UPDATES_KEY = 'UPDATES_KEY';
|
||||||
|
|
||||||
|
export default async () => {
|
||||||
|
invariant(
|
||||||
|
process.env.SECRET_KEY && process.env.URL,
|
||||||
|
'SECRET_KEY or URL env var is not set'
|
||||||
|
);
|
||||||
|
const secret = process.env.SECRET_KEY.slice(0, 6) + process.env.URL;
|
||||||
|
const id = crypto.createHash('sha256').update(secret).digest('hex');
|
||||||
|
|
||||||
|
const [
|
||||||
|
userCount,
|
||||||
|
teamCount,
|
||||||
|
collectionCount,
|
||||||
|
documentCount,
|
||||||
|
] = await Promise.all([
|
||||||
|
User.count(),
|
||||||
|
Team.count(),
|
||||||
|
Collection.count(),
|
||||||
|
Document.count(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const body = JSON.stringify({
|
||||||
|
id,
|
||||||
|
version: 1,
|
||||||
|
clientVersion: packageInfo.version,
|
||||||
|
analytics: {
|
||||||
|
userCount,
|
||||||
|
teamCount,
|
||||||
|
collectionCount,
|
||||||
|
documentCount,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await client.del('UPDATES_KEY');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(UPDATES_URL, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body,
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
if (data.severity) {
|
||||||
|
await client.set(
|
||||||
|
UPDATES_KEY,
|
||||||
|
JSON.stringify({
|
||||||
|
severity: data.severity,
|
||||||
|
message: data.message,
|
||||||
|
url: data.url,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (_e) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
};
|
Reference in New Issue