Skip to content
This repository has been archived by the owner on Feb 9, 2024. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pmb0 committed Jan 8, 2018
1 parent e532fef commit 110cf5a
Show file tree
Hide file tree
Showing 36 changed files with 186,620 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
14 changes: 14 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
root: true,
extends: 'standard',
rules: {
'comma-dangle': [1, 'only-multiline'],
'indent': ['error', 2, {MemberExpression: 1 }],
'space-before-function-paren': 0
},
env: {
node: true,
mocha: true,
es6: true
}
}
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=https://registry.npmjs.org/
22 changes: 22 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
language: node_js
sudo: false
node_js:
- '8'
- '7'
script:
- yarn test
before_install: yarn global add greenkeeper-lockfile@1
before_script: greenkeeper-lockfile-update
after_script: greenkeeper-lockfile-upload
deploy:
provider: npm
email: [email protected]
api_key:
secure: nOzv569aM6CHxo4rJVrosQucXhpygG72BfBLHRtJK8HfLP7pyuLQ9NgWjqSpxoVqP96qDajh3EaTb5s6v4T02ezGyOMeA/Ly0E5La2Yx3/Ava1EHqB61AGMvALPG6f38Gw4gCSoddD+lndWbtvzkXGCbVS3EAoKE5AYzfEHXpsAk9NTIZdeXUHgBc8L0pu9C85rJ4haaiLJmQLVWWeRHWIrTCFWfhfwj5LR4I0aAaPmewT8Ej9KWDLkJoyJ/PezXhykNMBIJGUbHb1XWadtuQUsoH4VusZtH2mes3KzlHyR6/Z4U9HszpkhQlj/hWNdF/sKP9mwSejwDp5DJtatHuC1TTJWO7+eWgjrJYJpX5/gJi1s1WLcrDLx6/6qxZhWJ57hVrvnaaiPGS+hZMLaD9+PUl58Fi4JbRycw9mwti6YePHnJRhvWl2S+9LY9nc1VJQuXcix3pki5Gg7WJmDntehuRUns/0NLJvy5UsBOd/RHPdUvshDX2ncpDFh4uwJKCBHyJKdScgbr61iWiSJny+Y1asWFy7KtGg2YOxa2ssbyzbBVMa9dUUeBJfwXeQPsYAqKm5IjLvhYRalzdGQbnUQf8wVyXMVBv9TMmLPx0GRot7rYC8wpZ0CQPVWU3WBojBoY129r2AJdWQGUva2NqjcTry7fE/IT4lWIEr7SlgY=
on:
tags: true
repo: heiseonline/embetty-server
node_js: '8'
env:
global:
secure: ZJ2A+YqqLfcRmOYG6+36ZapATBi2sVRjvHr+o6rVHfFIz6ltQCam2HvPmaHjIEu5A/ha1kktMtFFzWXiz2MjaGGe2754Xcv91832Uq9F5bxnHimDM6EeCS6EMvWyqwuaRKTSFoSJA4S8QvCWkTEVr/LkUTdxwDAKa/VXtxi4/E2D9cz28tKMEUFh4EVRewB8XOmg38VjGuoy9QtuHF/iXAif4TsPu9wXCRvLtdW00dyRAsKj2myHPbuvZTW1w5hBi4u7B3TcwxmORxBrDHmppU8IioVpIHhHnR81RdSJkqjq6ehch3B4HpMeFt0XyJTedHjtFMN7Kn+n1y8tLcscbdazsS8GgzFpq6tWWfkGhI9hJ0hucwaXXm8HZudlaBIQaizEMScwYiq8kHq7P1dyKl24WFpTf9kJivU+j110s+oxpiRXRVaDcbyJ51c+RnqSzc3KMDtJX8zk/bN+J83wXdkOIBsHgehKQgb7PhMGAiiVtaxZt/h9bp0iMScXwd/MUlGA5XUizU46EE3BkU9meD110RJFUAHfCc64YIfTJmCoa6wpOIRQ0ZoTsWlWAMayHL/k0ZFQXDRY/rGuwk8NNFndniq+J0fsVhGVQhOYk4UXxwskutSJf2LUYa3lOVF/NHni7msYbuQFFYV06pB2NekrZu3Xj2Zsjc6JEX+bLec=
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# embetty-server

## Starting the Embetty Server

```sh
$ npm install
$ npm start
```

or

```sh
$ yarn
$ yarn start
```

## Configuration

| Variable | Description |
|----------|-------------|
| `DEBUG` | This variable controls the output of log messages. You may set it to `embetty.*` to log all Embetty messages to `STDOUT`. |
| `EMBETTY_CACHE`| Connection string of a cache adapter. Currently [Redis](https://www.iana.org/assignments/uri-schemes/prov/redis) (example: `redis://`) and LRU (example: `lru://`) are supported. |
| `NODE_ENV` | This variable should be set to `production` in production environments. |
| `PORT` | This variable can be used to specify the port on which Embetty Server listens. Default: `3000` |
| `VALID_ORIGINS` | Contains a comma-separated list of allowed [origins](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin). Must be specified. Examples: `https://example.com`, `https://a.example.com,https://b.example.com` or `*`. |

## Running the tests

```sh
$ yarn test
```
51 changes: 51 additions & 0 deletions bin/www
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env node

const app = require('../')
const debug = require('debug')('embetty.web:server')
const http = require('http')

const port = normalizePort(process.env.PORT || '3000')
app.set('port', port)

const server = http.createServer(app)

server.listen(port)
server.on('error', onError)
server.on('listening', onListening)

function normalizePort(val) {
const port = parseInt(val, 10)
if (isNaN(port)) return val
if (port >= 0) return port
return false
}

function onError(error) {
if (error.syscall !== 'listen') {
throw error
}

const bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges')
process.exit(1)
case 'EADDRINUSE':
console.error(bind + ' is already in use')
process.exit(1)
default:
throw error
}
}

function onListening() {
const addr = server.address()
const bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port
debug('Listening on ' + bind)
}
29 changes: 29 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const {NotFound} = require('./lib/exceptions')
const Embetty = require('@heise/embetty-base')
const express = require('express')
const helmet = require('helmet')
const logger = require('morgan')
const routes = require('./routes')

const app = express()

app.set('embetty', new Embetty())

app.use(logger(process.env.NODE_ENV === 'production' ? 'short' : 'dev', {
skip: (req, res) => process.env.NODE_ENV === 'test'
}))

app.use(helmet())
app.use('/', routes)

app.use((req, res, next) => {
next(NotFound)
})

app.use((err, req, res, next) => {
err.statusCode = err.statusCode || 500
if (err.statusCode >= 500) console.error(err)
res.sendStatus(err.statusCode)
})

module.exports = app
10 changes: 10 additions & 0 deletions lib/exceptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const BadRequest = new Error()
BadRequest.statusCode = 400

const NotFound = new Error()
NotFound.statusCode = 404

const Forbidden = new Error()
Forbidden.statusCode = 403

module.exports = {BadRequest, Forbidden, NotFound}
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@heise/embetty-server",
"version": "1.0.0",
"main": "index.js",
"repository": "[email protected]:heiseonline/embetty-server.git",
"author": "Philipp Busse <[email protected]>",
"license": "MIT",
"private": false,
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www",
"test": "NODE_ENV=test mocha --bail --check-leaks"
},
"devDependencies": {
"@heise/request-promise-native-record": "^1.0.1",
"mocha": "^4.0.1",
"nodemon": "^1.12.1",
"supertest": "^3.0.0"
},
"dependencies": {
"@heise/embetty-base": "../embetty-base",
"cors": "^2.8.4",
"debug": "~2.6.9",
"express": "^4.16.2",
"helmet": "^3.9.0",
"morgan": "~1.9.0"
}
}
28 changes: 28 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const {Forbidden} = require('../lib/exceptions')
const cors = require('cors')
const debug = require('debug')('embetty.web:server')
const express = require('express')
const tweet = require('./tweet')
const video = require('./video')

const router = express.Router()

function getValidOrigins() {
const _validOrigins = process.env.VALID_ORIGINS || ''
return _validOrigins.length > 0 ? _validOrigins.split(',') : []
}

router.use(cors({
origin: (origin, cb) => {
const validOrigins = getValidOrigins()
if (!origin || validOrigins.indexOf(origin) !== -1) return cb(null, true)

debug('Invalid origin:', origin, 'Valid:', validOrigins)
cb(Forbidden)
}
}))

router.use('/tweet', tweet)
router.use('/video', video)

module.exports = router
58 changes: 58 additions & 0 deletions routes/tweet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const {BadRequest, NotFound} = require('../lib/exceptions')
const express = require('express')

const router = express.Router()

router.param('id', async (req, res, next, id) => {
try {
if (!/^\d+$/.test(id)) throw BadRequest
req.tweet = await req.app.get('embetty').loadTweet(id)
next()
} catch (e) {
next(e)
}
})

router.param('number', (req, res, next, number) => {
if (!/^\d+$/.test(number)) return next(BadRequest)
next()
})

router.get('/:id/profile-image', async (req, res, next) => {
try {
const image = await req.tweet.getProfileImage()
if (!image) return next(NotFound)
res.type(image.type)
res.send(image.data)
} catch (e) {
next(e)
}
})

router.get('/:id/link-image', async (req, res, next) => {
try {
const image = await req.tweet.getLinkImage()
if (!image) return next(NotFound)
res.type(image.type)
res.send(image.data)
} catch (e) {
next(e)
}
})

router.get('/:id/images/:number', async (req, res, next) => {
try {
const image = await req.tweet.getImage(req.params.number)
if (!image) return next(NotFound)
res.type(image.type)
res.send(image.data)
} catch (e) {
next(e)
}
})

router.get('/:id', (req, res) => {
res.send(req.tweet)
})

module.exports = router
12 changes: 12 additions & 0 deletions routes/video.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const express = require('express')
const facebook = require('./video/facebook')
const vimeo = require('./video/vimeo')
const youtube = require('./video/youtube')

const router = express.Router()

router.use('/youtube', youtube)
router.use('/vimeo', vimeo)
router.use('/facebook', facebook)

module.exports = router
Loading

0 comments on commit 110cf5a

Please sign in to comment.