Skip to content

Commit

Permalink
Adds Heroku support and env config support
Browse files Browse the repository at this point in the history
bumps version to 3.3.5 and syncs all sub-repositories
adds heroku button to README
adds app.json Heroku Configuration file
adds heroku-postbuild script to main package.json
adds start script to main package.json
adds engines to main package.json
upgrades obojobo-express config to support loading config vars from ENV
adds support for Heroku's DATABASE_URL env var for database configuration
adds support for default config options
removes need for hostname config
  • Loading branch information
iturgeon committed Oct 1, 2018
1 parent 59c53a2 commit 2f46276
Show file tree
Hide file tree
Showing 18 changed files with 213 additions and 69 deletions.
1 change: 1 addition & 0 deletions .yarnrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
workspaces-experimental true
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ To keep our collective efforts aimed in the same direction, we've outlined what
* [PosgreSQL](https://www.postgresql.org/) Database
* [Docker](https://www.docker.com/) (for development)

## Quick Heroku Deploy

We added Heroku support as an easy way to give Obojobo a **free test drive** (or scale it up for production use).

[![Deploy Obojobo to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/ucfopen/Obojobo/)

> [Heroku](https://www.heroku.com/what) is a cloud service that lets you host web apps in the cloud without worring so much the infrastructure.
## Development Setup

1. Clone this repo
Expand Down
57 changes: 57 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "Obojobo Next",
"description": "Run Obojobo Next on Heroku",
"keywords": [
"education",
"edtech",
"obojobo",
"openedu",
"open education",
"learning"
],
"website": "https://ucfopen.github.io/Obojobo-Docs/",
"logo": "https://ucfopen.github.io/Obojobo-Docs/assets/images/obojobo_white.svg",
"success_url": "/firstrun",
"scripts": {
"postdeploy": "cd node_modules/obojobo-document-engine && yarn build && cd ../obojobo-express && yarn db:migrateup"
},
"env": {
"OBO_LTI_SECRET": {
"description": "LTI Secret used for default key 'obo-next-production-lit-key'",
"generator": "secret"
},
"OBO_COOKIE_SECRET": {
"description": "Secret string used to encrypt cookie data",
"generator": "secret"
},
"DEBUG": {
"description": "Select which logs to write to the error log",
"value": "obojobo_server:error,obojobo_server:warn"
},
"YARN_PRODUCTION": {
"description": "Makes sure yarn install includes dev dependencies",
"value": "false"
}
},
"formation": {
"web": {
"quantity": 1,
"size": "free"
}
},
"image": "heroku/nodejs",
"addons": [
{
"plan": "heroku-postgresql:hobby-dev",
"options": {
"version": "9.6"
}
}
],
"buildpacks": [
{
"url": "heroku/nodejs"
}
],
"environments": {}
}
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
"private": true,
"name": "obojobo-next",
"scripts": {
"start": "cd node_modules/obojobo-express && node ./bin/www",
"setup": "cd node_modules/obojobo-document-engine && yarn build && cd ../obojobo-express && yarn db:rebuild",
"dev": "cd node_modules/obojobo-express && yarn dev",
"dev:docEngine": "concurrently \"cd node_modules/obojobo-express && yarn dev\" \" cd node_modules/obojobo-document-engine && yarn start\"",
"test": "cd node_modules/obojobo-document-xml-parser && yarn test && cd ../obojobo-express && yarn test && cd ../obojobo-document-engine && yarn test",
"precommit": "cd node_modules/obojobo-express && yarn precommit && cd ../obojobo-document-engine && yarn precommit"
"precommit": "cd node_modules/obojobo-express && yarn precommit && cd ../obojobo-document-engine && yarn precommit",
"heroku-postbuild": "cd node_modules/obojobo-document-engine && yarn build && cd ../obojobo-express && yarn assets"
},
"devDependencies": {
"concurrently": "^3.5.0",
Expand All @@ -16,5 +18,9 @@
"packages/obojobo-document-engine",
"packages/obojobo-document-xml-parser",
"packages/obojobo-express"
]
],
"engines": {
"node": "^6.9.4",
"yarn": "^1.0"
}
}
2 changes: 1 addition & 1 deletion packages/obojobo-document-engine/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obojobo-document-engine",
"version": "1.0.3",
"version": "3.3.5",
"description": "",
"engines": {
"yarn": "^1.0"
Expand Down
2 changes: 1 addition & 1 deletion packages/obojobo-document-xml-parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"xml-js": "^1.0.2"
},
"name": "obojobo-document-xml-parser",
"version": "0.3.0",
"version": "3.3.5",
"main": "xml2draft.js",
"devDependencies": {
"jest": "22.4.3"
Expand Down
3 changes: 2 additions & 1 deletion packages/obojobo-express/__tests__/routes/lti.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const mockReq = {
},
get: jest.fn()
},
getCurrentUser: jest.fn()
getCurrentUser: jest.fn(),
get: () => 'hostname' // used to mock req.get('host')
}

describe('lti route', () => {
Expand Down
14 changes: 11 additions & 3 deletions packages/obojobo-express/bin/sample_draft.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ let usageError = new Error(`Usage:
node sample_draft.js seed
node sample_draft.js watch`)
let defaultId = '00000000-0000-0000-0000-000000000000'
let sampleJsonPath = path.join(__dirname, '..', '..', '..', 'node_modules', 'obojobo-document-engine', 'test-object.json')
let sampleJsonPath = path.join(
__dirname,
'..',
'..',
'..',
'node_modules',
'obojobo-document-engine',
'test-object.json'
)
let writeJsonDraftToDbPath = `${__dirname}/write_json_draft_to_db`
let db = oboRequire('db')

Expand All @@ -36,7 +44,7 @@ try {

exec(cmd, {}, (err, stdout, stderr) => {
if (err) {
throw(err)
throw err
}

console.log(
Expand All @@ -57,7 +65,7 @@ try {
{},
(err, stdout, stderr) => {
if (err) {
throw(err)
throw err
}

console.info('Sample JSON Draft changed, updating...')
Expand Down
80 changes: 66 additions & 14 deletions packages/obojobo-express/config.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,83 @@
let fs = require('fs')
let logger = require('./logger')
let configuration = {}
let env = 'development'

if (process.env.NODE_ENV) {
env = process.env.NODE_ENV
}

let getConfigFileData = (configFile, type = null) => {
let json = JSON.parse(fs.readFileSync(configFile))
return type ? json[type] : json
// if DATABASE_URL is set, use it to override the other database params
// expects DATABASE_URL to be HEROKU format like 'postgres://user:password@domain:port/dbname'
// NOTE db-migrate commands will automatically use HEROKU's DATABASE_URL, skipping our config
if (process.env.DATABASE_URL){
let url = require('url')
let dburl = url.parse(process.env.DATABASE_URL)
process.env.DB_USER = dburl.auth.split(':')[0]
process.env.DB_PASS = dburl.auth.split(':')[1]
process.env.DB_HOST = dburl.hostname
process.env.DB_NAME = dburl.path.substring(1)
process.env.DB_PORT = dburl.port
}

let addToConfig = function(configFile, type, propertyName) {
configuration[propertyName] = getConfigFileData(configFile, type)
return configuration[propertyName]
let replaceENVsInObject = json => {
let rawJson = JSON.stringify(json) // convert back to string

// replace any "ENV": "CONFIG_VAR" settings with
// values from procesess.env
let pattern = /\{\s*"ENV"\s*?:\s*?"(.*?)"\s*\}/gi
let result

let replacedJson = rawJson
while( (result = pattern.exec(rawJson)) ){
if(!process.env[result[1]]){
throw new Error(`Expected ENV var ${result[1]} is not set`)
}
else{
let replacement = process.env[result[1]]
// if the value isnt true, false, or an integer, wrap it with quotes
if(replacement !== 'true' && replacement !== 'false' && !(/^\d+$/g.test(replacement))){
replacement = `"${replacement}"`
}
// replace without changing pattern.exec()'s position in rawJson
replacedJson = replacedJson.replace(result[0], replacement)
}
}

json = JSON.parse(replacedJson) // convert back to object
return json
}

let getConfigFileData = (configFile, env) => {
try{
let rawJson = fs.readFileSync(configFile) // load
let json = JSON.parse(rawJson) // parse
let defaultObject = json.default ? json.default : {}
let envObject = json[env] ? json[env] : {}

if(!json[env] && !json.default){
throw new Error(`Missing config environment for "default" and "${env}"`)
}

if(json[env]){
envObject = replaceENVsInObject(envObject)
}

return Object.assign({}, defaultObject, envObject) // combine with default if it exists

} catch (error){
logger.error(`Error loading config file: ${configFile}`)
logger.error(error)
}
return {}
}

let db = getConfigFileData('./config/db.json', env)
// convert the json in db.json to an object our database libraries like
configuration.db = {
host: db.host,
port: db.port,
database: db.database,
user: db.user,
password: db.password
let addToConfig = function(configFile, env, configGroup) {
configuration[configGroup] = getConfigFileData(configFile, env)
return configuration[configGroup]
}

addToConfig('./config/db.json', env, 'db')
addToConfig('./config/lti.json', env, 'lti')
addToConfig('./config/permission_groups.json', env, 'permissions')
addToConfig('./config/draft.json', env, 'draft')
Expand Down
11 changes: 9 additions & 2 deletions packages/obojobo-express/config/db.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@
"password": "mysecretpassword",
"host": "127.0.0.1",
"database": "postgres",
"port": 5432,
"schema": ""
"port": 5432
},
"production":{
"driver": "postgres",
"user": {"ENV": "DB_USER"},
"password": {"ENV": "DB_PASS"},
"host": {"ENV": "DB_HOST"},
"database": {"ENV": "DB_NAME"},
"port": {"ENV": "DB_PORT"}
}
}
5 changes: 1 addition & 4 deletions packages/obojobo-express/config/draft.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"development": {
"excludeModules":[]
},
"production": {
"default": {
"excludeModules":[]
}
}
16 changes: 10 additions & 6 deletions packages/obojobo-express/config/general.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
{
"development": {
"hostname": "127.0.0.1:8080",
"cookieSecret": "REPLACE_ME_WITH_YOUR_SECRET",
"default": {
"cookieName": "obo_next",
"secureCookie": false,
"secureCookie": true,
"bodyParser": {
"jsonOptions": {
"limit": "1mb"
"limit": "2mb"
},
"textOptions": {
"limit": "1mb"
"limit": "2mb"
},
"urlencodedOptions": {
"extended": false
}
}
},
"development": {
"cookieSecret": "REPLACE_ME_WITH_YOUR_SECRET"
},
"production": {
"cookieSecret": {"ENV": "OBO_COOKIE_SECRET"}
}
}
8 changes: 6 additions & 2 deletions packages/obojobo-express/config/lti.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
{
"development":{
"keys":{
"testkey": "testsecret",
"key2": "secret2"
"testkey": "testsecret"
}
},
"production":{
"keys":{
"obo-next-production-lti-key": {"ENV": "OBO_LTI_SECRET"}
}
}
}
2 changes: 1 addition & 1 deletion packages/obojobo-express/config/permission_groups.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"development": {
"default": {
"canViewEditor": ["Instructor", "Administrator"],
"canEditDrafts": ["Instructor", "Administrator"],
"canDeleteDrafts": ["Instructor", "Administrator"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,23 @@ exports.setup = function(options, seedLink) {
}

exports.up = function(db) {
return db
.removeColumn('attempts_question_responses', 'responder_id')
.then(result => {
return db.addIndex(
'attempts_question_responses',
'aqr_unique_responses',
['attempt_id', 'question_id'],
true
)
})
return db.removeColumn('attempts_question_responses', 'responder_id').then(result => {
return db.addIndex(
'attempts_question_responses',
'aqr_unique_responses',
['attempt_id', 'question_id'],
true
)
})
}

exports.down = function(db) {
return db
.removeIndex('attempts_question_responses', 'aqr_unique_responses')
.then(result => {
return db.addColumn('attempts_question_responses', 'responder_id', {
type: 'varchar',
length: 100
})
return db.removeIndex('attempts_question_responses', 'aqr_unique_responses').then(result => {
return db.addColumn('attempts_question_responses', 'responder_id', {
type: 'varchar',
length: 100
})
})
}

exports._meta = {
Expand Down
Loading

0 comments on commit 2f46276

Please sign in to comment.