├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── app ├── index.js └── templates │ ├── loopback │ ├── .env.example │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── LICENSE │ ├── README.md │ ├── client │ │ └── README.md │ ├── package.json │ └── server │ │ ├── _datasources.js │ │ ├── boot │ │ ├── authentication.js │ │ └── root.js │ │ ├── component-config.json │ │ ├── config.json │ │ ├── datasources.development.js │ │ ├── datasources.json │ │ ├── datasources.production.js │ │ ├── middleware.development.json │ │ ├── middleware.json │ │ ├── model-config.json │ │ └── server.js │ ├── migrations │ ├── .gitignore │ ├── 20161105183352-accesstoken.js │ ├── 20161105183353-acl.js │ ├── 20161105183354-role.js │ ├── 20161105183355-rolemapping.js │ ├── 20161105183356-user.js │ ├── 20161105183357-logger.js │ └── database.example.json │ └── winston │ └── 01-winston.js └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "node": true, 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "globalReturn": true, 7 | "ecmaFeatures": { 8 | "jsx": true 9 | } 10 | }, 11 | "rules": { 12 | "max-len": ["warn", 120, 2, {"ignoreUrls": true}], 13 | "comma-dangle": 0, 14 | "one-var": 0, 15 | "semi": 2 16 | } 17 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gitignore 3 | /node_modules 4 | /app/templates/migrations/database.json 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Stanislav Tarasenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Loopback-PostgreSQL generator 2 | 3 | ## Description 4 | 5 | Loopback-PostgreSQL generator is a [yeoman] (https://github.com/yeoman/generator) package that allows you to scaffold a new REST API loopback project that are using: 6 | 7 | * [LoopBack](https://github.com/strongloop/loopback) - Node.js REST API framework 8 | * [PostgreSQL](https://github.com/strongloop/loopback-connector-postgresql) - PostgreSQL loopback connector 9 | * [Winston](https://github.com/winstonjs/winston) - Logging module that configured to write in DB, logfile and console 10 | * [.env module](https://github.com/rolodato/dotenv-safe) - Library for .env credentials management 11 | * [DB migrations](https://github.com/db-migrate/node-db-migrate) - Database migration framework for Node.js, settings and commands are described below 12 | 13 | Also current boilerplate uses [S3 component](https://github.com/strongloop/loopback-component-storage) and SMTP. 14 | 15 | ## Install 16 | 17 | 1. Install: ```npm install -g generator-loopback-postgresql``` 18 | 2. Install yeoman: ```npm install -g yo``` if it isn't exist yet 19 | 3. Run: ```yo loopback-postgresql``` 20 | 21 | ## Usage 22 | 23 | After project generation you should edit your .env file and setup all correct credentials for your services. 24 | 25 | ### .env 26 | 27 | ``` 28 | BUCKET=default.bucket.name 29 | BUCKET_KEY=bucket.key 30 | BUCKET_KEY_ID=bucket.id 31 | 32 | RDS_HOSTNAME=localhost 33 | RDS_PORT=5432 34 | RDS_DBNAME=dbname 35 | RDS_USERNAME=postgres 36 | RDS_PASSWORD=postgres 37 | 38 | SMTP_HOST=smtp.host.name 39 | SMTP_USERNAME=smtp.user.name 40 | SMTP_PASSWORD=smtp.password 41 | 42 | DEBUG=* 43 | ``` 44 | 45 | [Loopback Debug values](https://loopback.io/doc/en/lb2/Setting-debug-strings.html#debug-strings-reference) 46 | 47 | ### Migrations 48 | You have an ability to work with migrations. 49 | Before start you must edit settings for this module. `./migrations/database.json` 50 | A new application has a few scripts for db migrations: 51 | 52 | ``` 53 | npm run migrate up 54 | ``` 55 | The up command executes the migrations of your currently configured migrations directory. 56 | 57 | ``` 58 | npm run migrate down 59 | ``` 60 | The down command executes the migrations of your currently configured migrations directory. 61 | 62 | ``` 63 | npm run migrate reset 64 | ``` 65 | The reset command is a shortcut to execute all down migrations and literally reset all migrations which where currently done. 66 | 67 | ``` 68 | npm run migrate create 69 | ``` 70 | The create command creates templates for you, there are several options for this. 71 | 72 | **Directory of migrations by default is located at: `./migrations/`** 73 | 74 | Further information about db migrations you can find on [this page](https://db-migrate.readthedocs.io/en/latest/Getting%20Started/the%20commands/). 75 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let generators = require('yeoman-generator'); 4 | let configs = {}; 5 | 6 | module.exports = generators.Base.extend({ 7 | prompting: function() { 8 | return this.prompt([{ 9 | type: 'list', 10 | name: 'version', 11 | message: 'What version of loopback do you prefer?', 12 | choices: ['2', '3'] 13 | }]).then(function(answers) { 14 | configs = answers; 15 | }.bind(this)); 16 | }, 17 | writing: function() { 18 | // Copy main files 19 | this.directory('./loopback', './'); 20 | this.fs.copyTpl( 21 | this.templatePath('./loopback/.env.example'), 22 | this.destinationPath('.env') 23 | ); 24 | 25 | this.fs.copyTpl( 26 | this.templatePath('./winston/'), 27 | this.destinationPath('./server/boot/') 28 | ); 29 | 30 | // Copy migrations 31 | this.fs.copyTpl( 32 | this.templatePath('./migrations/'), 33 | this.destinationPath('./migrations/') 34 | ); 35 | this.fs.copyTpl( 36 | this.templatePath('./migrations/database.example.json'), 37 | this.destinationPath('./migrations/database.json') 38 | ); 39 | }, 40 | install: function() { 41 | this.npmInstall('loopback@'+configs.version, {'save': true}); 42 | this.spawnCommandSync('npm', ['install']); 43 | this.spawnCommandSync('mkdir', ['runtime']); 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /app/templates/loopback/.env.example: -------------------------------------------------------------------------------- 1 | BUCKET=default.bucket.name 2 | BUCKET_KEY=bucket.key 3 | BUCKET_KEY_ID=bucket.id 4 | 5 | RDS_HOSTNAME=localhost 6 | RDS_PORT=5432 7 | RDS_DBNAME=dbname 8 | RDS_USERNAME=postgres 9 | RDS_PASSWORD=postgres 10 | 11 | SMTP_HOST=smtp.host.name 12 | SMTP_USERNAME=smtp.user.name 13 | SMTP_PASSWORD=smtp.password 14 | 15 | DEBUG=* 16 | -------------------------------------------------------------------------------- /app/templates/loopback/.eslintignore: -------------------------------------------------------------------------------- 1 | /client/ -------------------------------------------------------------------------------- /app/templates/loopback/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "node": true, 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "globalReturn": true, 7 | "ecmaFeatures": { 8 | "jsx": true 9 | } 10 | }, 11 | "rules": { 12 | "max-len": ["warn", 120, 2, {"ignoreUrls": true}], 13 | "comma-dangle": 0, 14 | "one-var": 0, 15 | "semi": 2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/templates/loopback/.gitignore: -------------------------------------------------------------------------------- 1 | *.csv 2 | *.dat 3 | *.log 4 | *.pid 5 | *.seed 6 | *.swo 7 | *.swp 8 | *.tgz 9 | .env 10 | .env.* 11 | !.env.example 12 | .strong-pm 13 | /node_modules 14 | -------------------------------------------------------------------------------- /app/templates/loopback/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Stanislav Tarasenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/templates/loopback/README.md: -------------------------------------------------------------------------------- 1 | # Loopback+PostgreSQL dummy application. 2 | 3 | It's the loopback dummy application. You can use it for a new projects. 4 | -------------------------------------------------------------------------------- /app/templates/loopback/client/README.md: -------------------------------------------------------------------------------- 1 | ## Client 2 | 3 | This is the place for your application front-end files. 4 | -------------------------------------------------------------------------------- /app/templates/loopback/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MyApplication", 3 | "version": "1.0.0", 4 | "main": "server/server.js", 5 | "scripts": { 6 | "lint": "./node_modules/eslint/bin/eslint.js .", 7 | "lint-fix": "./node_modules/eslint/bin/eslint.js . --fix", 8 | "start": "node .", 9 | "posttest": "npm run lint", 10 | "migrate": "node ./node_modules/db-migrate/bin/db-migrate --config ./migrations/database.json" 11 | }, 12 | "dependencies": { 13 | "compression": "^1.0.3", 14 | "cors": "^2.5.2", 15 | "helmet": "^1.3.0", 16 | "lodash": "^4.16.6", 17 | "loopback-boot": "^2.23.0", 18 | "loopback-component-explorer": "^2.7.0", 19 | "loopback-component-storage": "^1.10.0", 20 | "loopback-connector-postgresql": "^2.7.0", 21 | "loopback-datasource-juggler": "^2.53.0", 22 | "serve-favicon": "^2.0.1", 23 | "strong-error-handler": "^1.0.1", 24 | "winston": "^2.3.0", 25 | "winston-postgresql": "^1.2.0" 26 | }, 27 | "devDependencies": { 28 | "db-migrate": "^0.10.0-beta.20", 29 | "db-migrate-pg": "^0.1.11", 30 | "dotenv-safe": "^2.3.1", 31 | "eslint": "^3.7.1", 32 | "eslint-config-google": "^0.7.0" 33 | }, 34 | "repository": { 35 | "type": "", 36 | "url": "" 37 | }, 38 | "license": "MIT", 39 | "description": "Simple description" 40 | } 41 | -------------------------------------------------------------------------------- /app/templates/loopback/server/_datasources.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | db: { 5 | name: 'postgres', 6 | connector: 'postgresql', 7 | host: process.env.RDS_HOSTNAME, 8 | port: process.env.RDS_PORT, 9 | database: process.env.RDS_DBNAME, 10 | username: process.env.RDS_USERNAME, 11 | password: process.env.RDS_PASSWORD 12 | }, 13 | email: { 14 | name: 'email', 15 | connector: 'mail', 16 | transports: [ 17 | { 18 | type: 'SMTP', 19 | host: process.env.SMTP_HOST, 20 | secure: false, 21 | port: 587, 22 | auth: { 23 | user: process.env.SMTP_USERNAME, 24 | pass: process.env.SMTP_PASSWORD 25 | } 26 | } 27 | ] 28 | }, 29 | storage: { 30 | name: 'storage', 31 | connector: 'loopback-component-storage', 32 | provider: 'amazon', 33 | key: process.env.BUCKET_KEY, 34 | keyId: process.env.BUCKET_KEY_ID, 35 | bucket: process.env.BUCKET, 36 | allowedContentTypes: ['image/jpg', 'image/jpeg', 'image/png', 'application/pdf'], 37 | maxFileSize: 30 * 1024 * 1024 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /app/templates/loopback/server/boot/authentication.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function enableAuthentication(server) { 4 | server.enableAuth(); 5 | }; 6 | -------------------------------------------------------------------------------- /app/templates/loopback/server/boot/root.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(server) { 4 | // Install a `/` route that returns server status 5 | /* eslint-disable */ 6 | let router = server.loopback.Router(); 7 | /* eslint-enable */ 8 | router.get('/', server.loopback.status()); 9 | server.use(router); 10 | }; 11 | -------------------------------------------------------------------------------- /app/templates/loopback/server/component-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "loopback-component-explorer": { 3 | "mountPath": "/explorer" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /app/templates/loopback/server/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "restApiRoot": "/api", 3 | "host": "0.0.0.0", 4 | "port": 3000, 5 | "remoting": { 6 | "context": false, 7 | "rest": { 8 | "normalizeHttpPath": false, 9 | "xml": false 10 | }, 11 | "json": { 12 | "strict": false, 13 | "limit": "100kb" 14 | }, 15 | "urlencoded": { 16 | "extended": true, 17 | "limit": "100kb" 18 | }, 19 | "cors": false, 20 | "handleErrors": false 21 | }, 22 | "legacyExplorer": false 23 | } 24 | -------------------------------------------------------------------------------- /app/templates/loopback/server/datasources.development.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./_datasources'); 2 | -------------------------------------------------------------------------------- /app/templates/loopback/server/datasources.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": { 3 | "name": "db" 4 | }, 5 | "email": { 6 | "name": "email" 7 | }, 8 | "storage": { 9 | "name": "storage" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/templates/loopback/server/datasources.production.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./_datasources'); 2 | -------------------------------------------------------------------------------- /app/templates/loopback/server/middleware.development.json: -------------------------------------------------------------------------------- 1 | { 2 | "final:after": { 3 | "strong-error-handler": { 4 | "params": { 5 | "debug": true, 6 | "log": true 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /app/templates/loopback/server/middleware.json: -------------------------------------------------------------------------------- 1 | { 2 | "initial:before": { 3 | "loopback#favicon": {} 4 | }, 5 | "initial": { 6 | "compression": {}, 7 | "cors": { 8 | "params": { 9 | "origin": true, 10 | "credentials": true, 11 | "maxAge": 86400 12 | } 13 | }, 14 | "helmet#xssFilter": {}, 15 | "helmet#frameguard": { 16 | "params": [ 17 | "deny" 18 | ] 19 | }, 20 | "helmet#hsts": { 21 | "params": { 22 | "maxAge": 0, 23 | "includeSubdomains": true 24 | } 25 | }, 26 | "helmet#hidePoweredBy": {}, 27 | "helmet#ieNoOpen": {}, 28 | "helmet#noSniff": {}, 29 | "helmet#noCache": { 30 | "enabled": false 31 | } 32 | }, 33 | "session": {}, 34 | "auth": {}, 35 | "parse": {}, 36 | "routes": { 37 | "loopback#rest": { 38 | "paths": [ 39 | "${restApiRoot}" 40 | ] 41 | } 42 | }, 43 | "files": {}, 44 | "final": { 45 | "loopback#urlNotFound": {} 46 | }, 47 | "final:after": { 48 | "strong-error-handler": {} 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/templates/loopback/server/model-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "sources": [ 4 | "loopback/common/models", 5 | "loopback/server/models", 6 | "../common/models", 7 | "./models" 8 | ], 9 | "mixins": [ 10 | "loopback/common/mixins", 11 | "loopback/server/mixins", 12 | "../common/mixins", 13 | "./mixins" 14 | ] 15 | }, 16 | "User": { 17 | "dataSource": "db" 18 | }, 19 | "AccessToken": { 20 | "dataSource": "db", 21 | "public": false 22 | }, 23 | "ACL": { 24 | "dataSource": "db", 25 | "public": false 26 | }, 27 | "RoleMapping": { 28 | "dataSource": "db", 29 | "public": false 30 | }, 31 | "Role": { 32 | "dataSource": "db", 33 | "public": false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/templates/loopback/server/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | if (process.env.NODE_ENV != 'production') 4 | require('dotenv-safe').load(); 5 | 6 | let loopback = require('loopback'); 7 | let boot = require('loopback-boot'); 8 | let winston = require('winston'); 9 | let app = module.exports = loopback(); 10 | 11 | app.start = function() { 12 | return app.listen(function() { 13 | app.emit('started'); 14 | let baseUrl = app.get('url').replace(/\/$/, ''); 15 | winston.info('Web server listening at: %s', baseUrl); 16 | if (app.get('loopback-component-explorer')) { 17 | let explorerPath = app.get('loopback-component-explorer').mountPath; 18 | winston.info('Browse your REST API at %s%s', baseUrl, explorerPath); 19 | } 20 | }); 21 | }; 22 | 23 | boot(app, __dirname, function(err) { 24 | if (err) throw err; 25 | 26 | if (require.main === module) 27 | app.start(); 28 | }); 29 | -------------------------------------------------------------------------------- /app/templates/migrations/.gitignore: -------------------------------------------------------------------------------- 1 | database.json 2 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183352-accesstoken.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('accesstoken', { 19 | id: {type: 'string', primaryKey: true, notNull: true}, 20 | userid: 'int', 21 | ttl: {type: 'int', defaultValue: 1209600}, 22 | created: 'timestamp with time zone' 23 | }, cb) 24 | }; 25 | 26 | exports.down = function(db, cb) { 27 | db.dropTable('accesstoken', cb); 28 | }; 29 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183353-acl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('acl', { 19 | id: {type: 'int', notNull: true, primaryKey: true, autoIncrement: true}, 20 | model: 'string', 21 | permission: 'string', 22 | property: 'string', 23 | accesstype: 'string', 24 | principaltype: 'string', 25 | principalid: 'int' 26 | }, cb); 27 | }; 28 | 29 | exports.down = function(db, cb) { 30 | db.dropTable('acl', cb); 31 | }; 32 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183354-role.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('role', { 19 | id: {type: 'int', notNull: true, primaryKey: true, autoIncrement: true}, 20 | name: {type: 'string', notNull: true}, 21 | description: 'text', 22 | created: 'timestamp with time zone', 23 | modified: 'timestamp with time zone' 24 | }, cb); 25 | }; 26 | 27 | exports.down = function(db, cb) { 28 | db.dropTable('role', cb); 29 | }; 30 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183355-rolemapping.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('rolemapping', { 19 | id: {type: 'int', notNull: true, primaryKey: true, autoIncrement: true}, 20 | principaltype: 'string', 21 | principalid: 'int', 22 | roleid: 'int' 23 | }) 24 | .then((result) => { 25 | return db.addIndex('rolemapping', 'rolemapping_principalid_idx', 'principalid', cb); 26 | }) 27 | .catch((err) => cb(err)); 28 | }; 29 | 30 | exports.down = function(db, cb) { 31 | db.dropTable('rolemapping', cb); 32 | }; 33 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183356-user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('user', { 19 | id: {type: 'int', notNull: true, primaryKey: true, autoIncrement: true}, 20 | realm: 'string', 21 | username: 'string', 22 | password: {type: 'string', notNull: true}, 23 | credentials: 'text', 24 | challenges: 'text', 25 | email: {type: 'string', notNull: true}, 26 | emailverified: 'boolean', 27 | verificationtoken: 'string', 28 | status: 'string', 29 | created: 'timestamp with time zone', 30 | lastupdated: 'timestamp with time zone' 31 | }, cb); 32 | }; 33 | 34 | exports.down = function(db, cb) { 35 | return db.dropTable('user', cb); 36 | }; 37 | -------------------------------------------------------------------------------- /app/templates/migrations/20161105183357-logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let dbm; 4 | let type; 5 | let seed; 6 | 7 | /** 8 | * We receive the dbmigrate dependency from dbmigrate initially. 9 | * This enables us to not have to rely on NODE_PATH. 10 | */ 11 | exports.setup = function(options, seedLink) { 12 | dbm = options.dbmigrate; 13 | type = dbm.dataType; 14 | seed = seedLink; 15 | }; 16 | 17 | exports.up = function(db, cb) { 18 | db.createTable('logs', { 19 | id: {type: 'int', notNull: true, primaryKey: true, autoIncrement: true}, 20 | level: 'string', 21 | msg: 'string', 22 | meta: 'json', 23 | ts: {type: 'timestamp with time zone DEFAULT now()'} 24 | }, cb); 25 | }; 26 | 27 | exports.down = function(db, cb) { 28 | db.dropTable('logs', cb); 29 | }; 30 | -------------------------------------------------------------------------------- /app/templates/migrations/database.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev": { 3 | "driver": "pg", 4 | "user": "postgres", 5 | "password": "postgres", 6 | "host": "localhost", 7 | "database": "dbname", 8 | "schema": "public" 9 | } 10 | } -------------------------------------------------------------------------------- /app/templates/winston/01-winston.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let winston = require('winston'); 4 | require('winston-postgresql').PostgreSQL; 5 | 6 | module.exports = (app) => { 7 | winston.remove(winston.transports.Console); 8 | winston.add(winston.transports.Console, { 9 | colorize: true 10 | }); 11 | winston.add(winston.transports.File, { 12 | filename: './runtime/logs.dat', 13 | maxsize: 10240000, 14 | tailable: true 15 | }); 16 | 17 | winston.add(winston.transports.PostgreSQL, { 18 | 'connString': `${process.env.RDS_USERNAME}:${process.env.RDS_PASSWORD}@${process.env.RDS_HOSTNAME}:${process.env.RDS_PORT}/${process.env.RDS_DBNAME}`, 19 | 'tableName': 'logs' 20 | }); 21 | 22 | winston.info('All log types are being duplicated into DB.'); 23 | 24 | if (process.env.DEBUG) 25 | winston.level = 'debug'; 26 | 27 | winston.info('The Winston is launched.'); 28 | winston.debug('The Winston debug mode is switched on.'); 29 | }; 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-loopback-postgresql", 3 | "version": "1.0.1", 4 | "description": "Loopback+PostgreSQL generator", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "./node_modules/eslint/bin/eslint.js .", 8 | "posttest": "npm run lint" 9 | }, 10 | "dependencies": { 11 | "yeoman-generator": "^0.24.1" 12 | }, 13 | "devDependencies": { 14 | "eslint": "^3.11.1", 15 | "eslint-config-google": "^0.7.1" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/stanislavT/generator-loopback-postgresql.git" 20 | }, 21 | "keywords": [ 22 | "yeoman-generator", 23 | "scaffold", 24 | "back-end", 25 | "loopback", 26 | "migrations", 27 | "postgresql", 28 | "winston", 29 | ".env", 30 | "strongloop" 31 | ], 32 | "author": "Stanislav Tarasenko", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/stanislavT/generator-loopback-postgresql/issues" 36 | }, 37 | "homepage": "https://github.com/stanislavT/generator-loopback-postgresql#readme" 38 | } 39 | --------------------------------------------------------------------------------