bootstrapped project
This commit is contained in:
parent
9b07e395b5
commit
0ee7b6f8cb
16 changed files with 346 additions and 0 deletions
5
.babelrc
Normal file
5
.babelrc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"transform-es2015-modules-commonjs"
|
||||||
|
]
|
||||||
|
}
|
32
.circleci/config.yml
Normal file
32
.circleci/config.yml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
version: 2
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
docker:
|
||||||
|
- image: docker:latest
|
||||||
|
environment:
|
||||||
|
- di: "nfpis/storage-upload"
|
||||||
|
- dtag: "latest"
|
||||||
|
working_directory: ~/storage-upload
|
||||||
|
steps:
|
||||||
|
- run:
|
||||||
|
name: Update and install SSH & Git
|
||||||
|
command: apk update && apk upgrade && apk add --no-cache bash git openssh
|
||||||
|
- checkout
|
||||||
|
- setup_remote_docker
|
||||||
|
- run:
|
||||||
|
name: Build docker image
|
||||||
|
command: |
|
||||||
|
docker build -t test .
|
||||||
|
docker build --build-arg NODE=production -t ${di}:build_${CIRCLE_BUILD_NUM} -t ${di}:${CIRCLE_SHA1} -t ${di}:${dtag} .
|
||||||
|
- deploy:
|
||||||
|
name: Push to docker
|
||||||
|
command: |
|
||||||
|
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
|
docker push ${di}
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
build_deploy:
|
||||||
|
jobs:
|
||||||
|
- build:
|
||||||
|
context: org-global
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -57,3 +57,9 @@ typings/
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# Local development config file
|
||||||
|
config/config.json
|
||||||
|
|
||||||
|
# lol
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
|
18
Dockerfile
Normal file
18
Dockerfile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
FROM node:slim
|
||||||
|
|
||||||
|
ARG NODE=development
|
||||||
|
|
||||||
|
ENV HOME=/app \
|
||||||
|
NODE_ENV=${NODE}
|
||||||
|
|
||||||
|
COPY package.json $HOME/
|
||||||
|
|
||||||
|
WORKDIR $HOME
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . $HOME/
|
||||||
|
|
||||||
|
EXPOSE 4020
|
||||||
|
|
||||||
|
CMD ["npm", "start"]
|
14
api/defaults.js
Normal file
14
api/defaults.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
export default function defaults(options, defaults) {
|
||||||
|
options = options || {}
|
||||||
|
|
||||||
|
Object.keys(defaults).forEach(function(key) {
|
||||||
|
if (typeof options[key] === 'undefined') {
|
||||||
|
// No need to do clone since we mostly deal with
|
||||||
|
// flat objects
|
||||||
|
options[key] = defaults[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return options
|
||||||
|
}
|
9
api/router.js
Normal file
9
api/router.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import Router from 'koa-router'
|
||||||
|
|
||||||
|
import * as test from './test/routes'
|
||||||
|
|
||||||
|
const router = new Router()
|
||||||
|
|
||||||
|
router.get('/api/test', test.testStatic)
|
||||||
|
|
||||||
|
export default router
|
9
api/test/routes.js
Normal file
9
api/test/routes.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import config from '../../config'
|
||||||
|
|
||||||
|
export async function testStatic(ctx) {
|
||||||
|
ctx.body = {
|
||||||
|
name: config.get('name'),
|
||||||
|
version: config.get('version'),
|
||||||
|
environment: config.get('NODE_ENV'),
|
||||||
|
}
|
||||||
|
}
|
58
config.js
Normal file
58
config.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
const _ = require('lodash')
|
||||||
|
const nconf = require('nconf')
|
||||||
|
|
||||||
|
// Helper method for global usage.
|
||||||
|
nconf.inTest = () => nconf.get('NODE_ENV') === 'test'
|
||||||
|
|
||||||
|
// Config follow the following priority check order:
|
||||||
|
// 1. package.json
|
||||||
|
// 2. Enviroment variables
|
||||||
|
// 3. config/config.json
|
||||||
|
// 4. config/config.default.json
|
||||||
|
|
||||||
|
|
||||||
|
// Load package.json for name and such
|
||||||
|
let pckg = require('./package.json')
|
||||||
|
|
||||||
|
pckg = _.pick(pckg, ['name', 'version', 'description', 'author', 'license', 'homepage'])
|
||||||
|
|
||||||
|
|
||||||
|
// Load overrides as first priority
|
||||||
|
nconf.overrides(pckg)
|
||||||
|
|
||||||
|
|
||||||
|
// Load enviroment variables as second priority
|
||||||
|
nconf.env()
|
||||||
|
|
||||||
|
|
||||||
|
// Load any overrides from the appropriate config file
|
||||||
|
let configFile = 'config/config.json'
|
||||||
|
|
||||||
|
/* istanbul ignore else */
|
||||||
|
if (nconf.get('NODE_ENV') === 'test') {
|
||||||
|
configFile = 'config/config.test.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (nconf.get('NODE_ENV') === 'production') {
|
||||||
|
configFile = 'config/config.production.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
nconf.file('main', configFile)
|
||||||
|
|
||||||
|
// Load defaults
|
||||||
|
nconf.file('default', 'config/config.default.json')
|
||||||
|
|
||||||
|
|
||||||
|
// Final sanity checks
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (typeof global.it === 'function' & !nconf.inTest()) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('Critical: potentially running test on production enviroment. Shutting down.')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = nconf
|
22
config/config.default.json
Normal file
22
config/config.default.json
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"NODE_ENV": "development",
|
||||||
|
"server": {
|
||||||
|
"port": 4020,
|
||||||
|
"host": "0.0.0.0"
|
||||||
|
},
|
||||||
|
"bunyan": {
|
||||||
|
"name": "storage-upload",
|
||||||
|
"streams": [{
|
||||||
|
"stream": "process.stdout",
|
||||||
|
"level": "debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"jwt": {
|
||||||
|
"secret": "this-is-my-secret",
|
||||||
|
"options": {
|
||||||
|
"expiresIn": 604800
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fileSize": 524288000
|
||||||
|
}
|
3
index.js
Normal file
3
index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
require('babel-register')
|
||||||
|
|
||||||
|
require('./server')
|
38
package.json
Normal file
38
package.json
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"name": "storage-upload",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "nodemon index.js",
|
||||||
|
"start": "node index.js",
|
||||||
|
"test": "env NODE_ENV=test mocha --require babel-register --recursive --reporter dot",
|
||||||
|
"docker": "docker run -it --rm --name my-running-script -v \"$PWD\":/usr/src/app -w /usr/src/app node:slim",
|
||||||
|
"docker:test": "npm run docker -- npm install && npm run test",
|
||||||
|
"docker:dev": "npm run docker -- npm install && npm run dev",
|
||||||
|
"docker:prod": "npm run docker -- npm install && npm run start"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/nfp-projects/storage-upload.git"
|
||||||
|
},
|
||||||
|
"author": "Jonatan Nilsson",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/nfp-projects/storage-upload/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/nfp-projects/storage-upload#readme",
|
||||||
|
"dependencies": {
|
||||||
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||||
|
"babel-register": "^6.26.0",
|
||||||
|
"koa": "^2.3.0",
|
||||||
|
"koa-router": "^7.2.1",
|
||||||
|
"nconf": "^0.8.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"assert-extended": "^1.0.1",
|
||||||
|
"mocha": "^4.0.1",
|
||||||
|
"nodemon": "^1.12.1",
|
||||||
|
"request-json": "^0.6.2"
|
||||||
|
}
|
||||||
|
}
|
0
public/.gitkeep
Normal file
0
public/.gitkeep
Normal file
13
server.js
Normal file
13
server.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import Koa from 'koa'
|
||||||
|
|
||||||
|
import config from './config'
|
||||||
|
import router from './api/router'
|
||||||
|
|
||||||
|
const app = new Koa()
|
||||||
|
|
||||||
|
app.use(router.routes())
|
||||||
|
app.use(router.allowedMethods())
|
||||||
|
|
||||||
|
const server = app.listen(config.get('server:port'))
|
||||||
|
|
||||||
|
export default server
|
89
test/helper.client.js
Normal file
89
test/helper.client.js
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import request from 'request-json'
|
||||||
|
|
||||||
|
import defaults from '../api/defaults'
|
||||||
|
import config from '../config'
|
||||||
|
|
||||||
|
function parseBody(body, reject) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(body)
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(body)
|
||||||
|
return reject(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function callback(resolve, reject) {
|
||||||
|
return (err, res, rawBody) => {
|
||||||
|
let body = rawBody
|
||||||
|
if (err) {
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
if (typeof body === 'string' && body) {
|
||||||
|
body = parseBody(body, reject)
|
||||||
|
}
|
||||||
|
if (res.statusCode >= 300 ||
|
||||||
|
res.statusCode < 200) {
|
||||||
|
return reject(body)
|
||||||
|
}
|
||||||
|
resolve(body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function createClient(host = config.get('server:port'), opts) {
|
||||||
|
let options = defaults(opts, {})
|
||||||
|
|
||||||
|
let client = request.createClient('', options)
|
||||||
|
let prefix
|
||||||
|
|
||||||
|
prefix = `http://localhost:${host}`
|
||||||
|
client.headers['x-request-id'] = 'asdf'
|
||||||
|
|
||||||
|
client.auth = (user) => {
|
||||||
|
// let m = helperDB.model('user', {
|
||||||
|
// id: user.id,
|
||||||
|
// level: (user.get && user.get('level')) || 1,
|
||||||
|
// institute_id: (user.get && user.get('institute_id')) || null,
|
||||||
|
// password: (user.get && user.get('password')) || null,
|
||||||
|
// })
|
||||||
|
// let token = jwt.createUserToken(m)
|
||||||
|
// client.headers.authorization = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple wrappers to wrap into promises
|
||||||
|
client.getAsync = (path) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
if (path.slice(0, 4) === 'http') {
|
||||||
|
return client.get(path, callback(resolve, reject))
|
||||||
|
}
|
||||||
|
client.get(prefix + path, callback(resolve, reject))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Simple wrappers to wrap into promises
|
||||||
|
client.saveFileAsync = (path, destination) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
client.saveFile(prefix + path, destination, callback(resolve, reject, true))
|
||||||
|
})
|
||||||
|
|
||||||
|
client.postAsync = (path, data) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
client.post(prefix + path, data, callback(resolve, reject))
|
||||||
|
})
|
||||||
|
|
||||||
|
client.putAsync = (path, data) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
client.put(prefix + path, data, callback(resolve, reject))
|
||||||
|
})
|
||||||
|
|
||||||
|
client.deleteAsync = (path) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
client.del(prefix + path, callback(resolve, reject))
|
||||||
|
})
|
||||||
|
|
||||||
|
client.sendFileAsync = (path, files, data) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
client.sendFile(prefix + path, files, data || {}, callback(resolve, reject))
|
||||||
|
})
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
8
test/helper.server.js
Normal file
8
test/helper.server.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// import _ from 'lodash'
|
||||||
|
// import sinon from 'sinon'
|
||||||
|
import server from '../server'
|
||||||
|
import client from './helper.client'
|
||||||
|
|
||||||
|
after(() => server.close())
|
||||||
|
|
||||||
|
export const createClient = client
|
22
test/server.test.js
Normal file
22
test/server.test.js
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import assert from 'assert-extended'
|
||||||
|
|
||||||
|
import * as server from './helper.server'
|
||||||
|
|
||||||
|
describe('Server', () => {
|
||||||
|
let client
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
client = server.createClient()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should run', () =>
|
||||||
|
assert.isFulfilled(
|
||||||
|
client.getAsync('/api/test')
|
||||||
|
)
|
||||||
|
.then(data => {
|
||||||
|
assert.ok(data)
|
||||||
|
assert.ok(data.name)
|
||||||
|
assert.ok(data.version)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
Loading…
Reference in a new issue