diff --git a/.travis.yml b/.travis.yml index c99ea03..1abf30e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,10 +21,8 @@ jobs: - docker build -t humanconnection/api-feathers . - script: - yarn install --frozen-lockfile --non-interactive - - yarn add codacy-coverage - - yarn run eslint - - cp config/cucumber.json config/local.json - - yarn run test:coverage + - yarn global add codacy-coverage + - yarn run ci - cat ./coverage/lcov.info | codacy-coverage after_success: diff --git a/README.md b/README.md index fb842b5..deffa7a 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,13 @@ The API for a better world. More information under [human-connection.org](https: > **Note:** This is only the API part of Human-Connection, you have to also checkout the [WebApp](https://github.com/Human-Connection/WebApp) which uses this API. -## Development +## Local installation > we recommand to install the project locally for the best development ease and performance Getting up and running is as easy as 1, 2, 3, 4 ... 5. -1. Make sure you have [NodeJS](https://nodejs.org/), [yarn](https://yarnpkg.com), [mongoDB](https://www.mongodb.com/download-center#community) installed. +1. Make sure you have a recent version of [NodeJS](https://nodejs.org/), [yarn](https://yarnpkg.com) and [mongoDB](https://www.mongodb.com/download-center#community) installed. 2. Clone this repo ``` bash @@ -35,87 +35,112 @@ Getting up and running is as easy as 1, 2, 3, 4 ... 5. $ cd ./API $ yarn ``` +4. Setup database seeder for local development (recommended) -4. Setup local mailserver (optional) - - > **Note:** + Run + ```sh + $ cp config/local.example.json config/local.json + ``` + +5. Setup local mailserver (optional) + + > **Note:** > *You only have to start that mailserver when you want to register, reset your password or test emails in any form, it > does not affect the rest of the application.* - - Copy `config/local.example.json` to `config/local.json` and install the [MailDev](https://github.com/djfarrelly/MailDev) + + Install the [MailDev](https://github.com/djfarrelly/MailDev) server to catch all sent emails in a nice web interface. - + ``` bash # install mail dev (only has to be done once) - $ npm install -g maildev - - # start the server, it will output the web url + $ yarn global add maildev + + # start the server, it will output the web url # which normally is http://localhost:1080 $ maildev ``` - + You could also insert your smtp credentials into the local.json but that is not recommended as all emails would be sent to the given addresses which should not happen in development. - -5. Start server - Make sure that the `data` folder exists according to the `mongod --dbpath` in `package.json` to write the data into, then start the server: +6. Start server + + You don't have a background process running for mongodb? + Just open another terminal and run: + + ```bash + # open up another terminal and run: + $ yarn run mongo + # or if you are on windows, run: + $ yarn run mongo:win + ``` + > ##### IMPORTANT for Windows users: + > - make sure you have mongo bin directory added to your PATH + + Start the API server with the following commands: ``` bash - # start mongodb, feathers and seed database $ yarn dev - $ yarn dev:win if you're on windows - # start mongodb, feathers without seeding the database - $ yarn dev:noseed - - # start mongodb, feathers for production + # without hot reload $ yarn start + # you can customize the environment like this: + $ NODE_ENV=production yarn start ``` - > ##### IMPORTANT for WIN users: - > - make sure you have mongo bin directory added to your PATH - > - if you picked another data directory during mongodb setup make sure - > to change package.json scripts section for key "dev:win" so it points to - > the proper path. Otherwise you will get missing data path errors from mongodb. - - If you did it right it will seed some fake data for you and downloads some images and avatar for faster development. - Now you should be able to list some post at [http://localhost:3030/contributions](http://localhost:3030/contributions) -6. Setup and Start Thumbnail Service (optional) + Now, your API should be running at [http://localhost:3030](http://localhost:3030). + If you seeded your database, you will see some contributions at [http://localhost:3030/contributions](http://localhost:3030/contributions). + +7. Setup and Start Thumbnail Service (optional) We are using [Thumbor](https://github.com/thumbor/thumbor) as a Thumbnail Microservice. You can install it locally if you like but this is totally optional. - + **Install OR use docker** - + - At first you have to [install](http://thumbor.readthedocs.io/en/latest/installing.html) it locally and start it in the console with `thumbor` **OR** run it with docker `docker run -p 8000:8000 apsl/thumbor` - Set the `thumbor.url` in `config/local.json` to `http://localhost:8888` (with docker `http://localhost:8000`) if not defined differently. The `thumbor.key` does not necessarily have to be defined, it just makes the URL more secure. - - > Do not forget to always start it if you choose that setup or otherwise you will not see any pictures at all. -## Local configuration + > Do not forget to always start it if you choose that setup or otherwise you will not see any pictures at all. -If you need to configure anything you can do so inside the `config/local.json` file. For that the `config/local.example.json` will contain always a minimal setup to get it working. +### Local configuration -If, f.ex., you want to change listen address, port or URL, you can do so. Entries in the `config/local.json` will override entries in the `config/default.json`. +You can override any default configuration in `config/local.json`. You can find +a list of availabe defaults in `config/default.json`. +See [node-config documentation](https://github.com/lorenwest/node-config/wiki/Configuration-Files) +for details. -**Note on the seeder configuration** -The seeder configuration has two properties: -- **dropDatabase:** drop the whole database on (re)start. -- **runOnInit:** run the seeder always on server (re)start (when database is empty). +E.g. if you want to access the server from your mobile over WiFi, you should +replace `localhost` in your settings with your IP address in the local network: +```json +{ + "host": "192.168.188.22", + "baseURL": "http://192.168.188.22:3030", + "frontURL": "http://192.168.188.22:3000" +} -> **Note** *You can switch the `dropDatabase` entry after seeding and it will persist the seeded data.* +``` ## Testing -Simply run `yarn test` and all your tests in the `test/` directory will be run. +Run the entire test suite with: +```bash +$ yarn run test +``` + +If you want you can run specific tests: +```bash +$ yarn run mocha +$ yarn run cucumber +``` + ## Scaffolding Feathers has a powerful command line interface. Here are a few things it can do: ``` bash -$ npm install -g feathers-cli # Install Feathers CLI +$ yarn global add feathers-cli # Install Feathers CLI $ feathers generate service # Generate a new Service $ feathers generate hook # Generate a new Hook @@ -129,7 +154,7 @@ For more information on all the framework related things visit [docs.feathersjs. The HC platform is documented in our [gitbook](https://www.gitbook.com/book/human-connection/documentation/) (work in progress). -## License +## License Copyright (c) 2018 [Human-Connection.org](https://human-connection.org) diff --git a/config/cucumber.json b/config/cucumber.json deleted file mode 100644 index d9505d5..0000000 --- a/config/cucumber.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "host": "localhost", - "port": 3030, - "baseURL": "http://localhost:3030", - "frontURL": "http://localhost:3000", - "smtpConfig": { - "host": "0.0.0.0", - "port": 1025, - "ignoreTLS": true - }, - "thumbor": { - "url": "", - "key": "" - }, - "seeder": { - "runOnInit": false, - "dropDatabase": false - }, - "defaultEmail": "no-replay@human-connection.org" -} diff --git a/config/default.json b/config/default.json index 7f3b4e6..3fb5557 100644 --- a/config/default.json +++ b/config/default.json @@ -11,14 +11,20 @@ "max": 100 }, "thumbor": { - "url": "", - "key": "" + "url": false, + "key": false }, "apiSecret": "TE9TqAk2xK[9EFJL", "sentry": {}, "seeder": { - "runOnInit": true, - "dropDatabase": true + "runOnInit": false, + "dropDatabase": false + }, + "defaultEmail": "no-reply@human-connection.org", + "smtpConfig": { + "host": "0.0.0.0", + "port": 1025, + "ignoreTLS": true }, "mongodb": "mongodb://localhost:27017/hc_api", "authentication": { diff --git a/config/local.example.json b/config/local.example.json index 8884088..a7d62cf 100644 --- a/config/local.example.json +++ b/config/local.example.json @@ -1,20 +1,6 @@ { - "host": "localhost", - "port": 3030, - "baseURL": "http://localhost:3030", - "frontURL": "http://localhost:3000", - "smtpConfig": { - "host": "0.0.0.0", - "port": 1025, - "ignoreTLS": true - }, - "thumbor": { - "url": "", - "key": "" - }, "seeder": { "runOnInit": true, "dropDatabase": false - }, - "defaultEmail": "no-replay@human-connection.org" + } } diff --git a/config/test.json b/config/test.json index 6bda5b5..5825f80 100644 --- a/config/test.json +++ b/config/test.json @@ -1,14 +1,5 @@ { "port": 3031, "baseURL": "http://localhost:3031", - "seeder": { - "runOnInit": false, - "dropDatabase": false - }, - "smtpConfig": { - "host": "0.0.0.0", - "port": 1025, - "ignoreTLS": true - }, "mongodb": "mongodb://localhost:27017/hc_api_test" } diff --git a/features/api/post.feature b/features/api/post.feature index cb3ae79..6667374 100644 --- a/features/api/post.feature +++ b/features/api/post.feature @@ -5,8 +5,7 @@ Feature: Import a post from an organization and publish it in Human Connection Background: - Given the Human Connection API is up and running - And there is a user in Human Connection with these credentials: + Given there is a user in Human Connection with these credentials: | email | password | | user@example.com | 1234 | diff --git a/features/api/usersettings.feature b/features/api/usersettings.feature index ce46b41..98f0389 100644 --- a/features/api/usersettings.feature +++ b/features/api/usersettings.feature @@ -4,8 +4,7 @@ Feature: Save current newsfeed filters to usersettings In order to see the same selection of content next time I log in Background: - Given the Human Connection API is up and running - And there is a user in Human Connection with these credentials: + Given there is a user in Human Connection with these credentials: | email | password | isVerified | | user@example.com | 1234 | true | diff --git a/features/env/database.js b/features/env/database.js index 281dc64..61333a3 100644 --- a/features/env/database.js +++ b/features/env/database.js @@ -1,7 +1,6 @@ /* eslint no-console: off */ const { Before, AfterAll, setWorldConstructor } = require('cucumber'); -process.env.NODE_ENV = 'test'; // write into the test database const backendApp = require('../../server/app'); function CustomWorld() { diff --git a/features/step_definitions/steps.js b/features/step_definitions/steps.js index 28964cf..385a3b3 100644 --- a/features/step_definitions/steps.js +++ b/features/step_definitions/steps.js @@ -4,9 +4,8 @@ const { Given, When, Then } = require('cucumber'); const fetch = require('node-fetch'); const { expect } = require('chai'); -const waitOn = require('wait-on'); -const hcBackendUrl = 'http://localhost:3030'; +const hcBackendUrl = 'http://localhost:3031'; let currentUser; let currentUserPassword; @@ -50,17 +49,6 @@ function postRequest(route, body, callback) { }); } -Given(/^the Human Connection API is up and running(?: on "http:\/\/localhost:3030")?/, (callback) => { - waitOn({ resources: ['tcp:3030'], timeout: 30000 }, (err) => { - if (err) throw (err); - return callback(); - }); -}); - -Given('there is a 3rd party application running, e.g. \'Democracy\'', () => { - // Just documentation -}); - Given('there is a user in Human Connection with these credentials:', function (dataTable) { const params = dataTable.hashes()[0]; currentUserPassword = params.password; diff --git a/package.json b/package.json index 9886ef5..fa3873f 100644 --- a/package.json +++ b/package.json @@ -33,26 +33,18 @@ "yarn": ">= 1.3.0" }, "scripts": { + "ci": "yarn run eslint && yarn run test:coverage", "clear": "rm -Rf tmp", - "test": "npm run mocha && npm run cucumber", - "test:coverage": "nyc --reporter=lcovonly --reporter=text-summary npm run test", - "test:mongo": "npm run eslint && cross-env NODE_ENV=test && nyc --reporter=lcovonly --reporter=text-summary npm run mocha:mongo", + "mongo": "mongod --dbpath data --quiet", + "mongo:win": "mongod --dbpath /data/db --quiet", + "test": "yarn run mocha && yarn run cucumber", + "test:coverage": "nyc --reporter=lcovonly --reporter=text-summary yarn run test", "eslint": "eslint server/. test/. features/. --config .eslintrc.json", - "start": "concurrently 'mongod' 'wait-on tcp:27017 && cross-env NODE_ENV=production node server/'", - "dev:debug": "npm run clear && concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && cross-env DEBUG=feathers && cross-env NODE_ENV=development nodemon --inspect server/'", - "dev": "npm run clear && concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && cross-env DEBUG=feathers && cross-env NODE_ENV=development nodemon server/'", - "dev:local": "sh scripts/run-local.sh", - "dev:noseed": "concurrently 'mongod --dbpath data' 'wait-on tcp:27017 && NODE_ENV=development DEBUG=feathers nodemon server/'", - "dev:win": "npm run clear && concurrently \"mongod --dbpath /data/db\" \"wait-on tcp:27017&&cross-env NODE_ENV=development&&cross-env DEBUG=feathers&& nodemon --inspect server/\"", - "mocha": "npm run clear && $npm_package_config_mocha", - "mocha:mongo": "$npm_package_config_concurrently '$npm_package_config_mongoDev &>/dev/null' 'wait-on tcp:27017 && npm run mocha'", - "cucumber": "npm run clear && concurrently --kill-others --success first 'cross-env NODE_ENV=test node server/' 'wait-on tcp:3030 && cross-env NODE_ENV=test cucumber-js'", - "cucumber:mongo": "npm run clear && concurrently --kill-others --success first '$npm_package_config_mongoDev &>/dev/null || sleep infinity' 'wait-on tcp:27017 && cross-env NODE_ENV=test node server/' 'wait-on tcp:3030 && cross-env NODE_ENV=test cucumber-js'" - }, - "config": { - "mongoDev": "mongod --dbpath data --quiet", - "mocha": "cross-env NODE_ENV=test node_modules/mocha/bin/_mocha test/ --recursive --timeout 10000 --exit", - "concurrently": "concurrently --kill-others --success first" + "start": "node server/", + "dev": "cross-env DEBUG=feathers* nodemon server/", + "dev:debug": "cross-env DEBUG=feathers* nodemon --inspect=0.0.0.0:9229 server/", + "mocha": "yarn run clear && cross-env NODE_ENV=test mocha --recursive --timeout 10000 --exit", + "cucumber": "concurrently --kill-others --success first 'cross-env NODE_ENV=test node server/' 'wait-on tcp:3031 && cross-env NODE_ENV=test cucumber-js'" }, "dependencies": { "@feathersjs/authentication": "^2.1.7", diff --git a/scripts/run-local.sh b/scripts/run-local.sh deleted file mode 100644 index 46a9ee2..0000000 --- a/scripts/run-local.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -# start app on the local network -LOCAL_IP=$(ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'); -env API_HOST=$LOCAL_IP env WEBAPP_BASE_URL=http://$LOCAL_IP:3000 env API_BASE_URL=http://$LOCAL_IP:3030 env THUMBOR_URL=http://$LOCAL_IP:8888 yarn dev diff --git a/server/index.js b/server/index.js index f56069c..de2061f 100644 --- a/server/index.js +++ b/server/index.js @@ -1,13 +1,4 @@ /* eslint-disable no-console */ -const fs = require('fs-extra'); -const path = require('path'); - -// setup local env is not available -let configDir = path.resolve('config'); -if (process.env.NODE_ENV !== 'production' && !fs.existsSync(configDir + '/local.json')) { - fs.copySync(configDir + '/local.example.json', configDir + '/local.json'); -} - const app = require('./app'); const port = app.get('port'); const host = app.get('host'); diff --git a/server/mongoose.js b/server/mongoose.js index 60bc6d7..f7a5faf 100644 --- a/server/mongoose.js +++ b/server/mongoose.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ const mongoose = require('mongoose'); const fs = require('fs-extra'); const path = require('path'); @@ -5,13 +6,14 @@ const path = require('path'); module.exports = function () { const app = this; + mongoose.Promise = global.Promise; mongoose.connect(app.get('mongodb'), { useMongoClient: true, autoReconnect: true, keepAlive: 1, connectTimeoutMS: 10000, socketTimeoutMS: 10000 - }, function () { + }).then(() => { if (process.env.NODE_ENV !== 'production' && app.get('seeder').dropDatabase === true) { mongoose.connection.dropDatabase().then(() => { app.debug('>>>>>> DROPED DATABASE <<<<<<'); @@ -25,7 +27,8 @@ module.exports = function () { } else { app.emit('mongooseInit'); } + },(err) => { + console.log(err); }); - mongoose.Promise = global.Promise; app.set('mongooseClient', mongoose); };