54 | Forbidden 55 |
56 |57 | <% if (typeof error !== 'undefined') { %> 58 | <%= error %> 59 | <% } else { %> 60 | You don't have permission to see the page you're trying to reach. 61 | <% } %> 62 |
63 |64 | Why might this be happening? 65 |
66 |├── api ├── models │ ├── .gitkeep │ ├── Customer.js │ ├── Driver.js │ ├── Store.js │ └── Car.js ├── services │ └── .gitkeep ├── controllers │ ├── .gitkeep │ └── CarController.js ├── policies │ └── sessionAuth.js └── responses │ ├── ok.js │ ├── badRequest.js │ ├── forbidden.js │ ├── serverError.js │ └── notFound.js ├── assets ├── images │ └── .gitkeep ├── templates │ └── .gitkeep ├── favicon.ico ├── robots.txt └── styles │ └── importer.less ├── config ├── locales │ ├── de.json │ ├── en.json │ ├── fr.json │ ├── es.json │ └── _README.md ├── bootstrap.js ├── env │ ├── development.js │ └── production.js ├── log.js ├── models.js ├── policies.js ├── routes.js ├── i18n.js ├── csrf.js ├── globals.js ├── cors.js ├── http.js ├── session.js ├── connections.js ├── local.js ├── views.js ├── blueprints.js └── sockets.js ├── tasks ├── register │ ├── default.js │ ├── syncAssets.js │ ├── build.js │ ├── compileAssets.js │ ├── buildProd.js │ ├── linkAssets.js │ ├── linkAssetsBuild.js │ ├── linkAssetsBuildProd.js │ └── prod.js ├── config │ ├── clean.js │ ├── uglify.js │ ├── cssmin.js │ ├── sync.js │ ├── less.js │ ├── concat.js │ ├── watch.js │ ├── coffee.js │ ├── copy.js │ ├── jst.js │ └── sails-linker.js ├── pipeline.js └── README.md ├── package.json ├── app.js ├── Gruntfile.js ├── views ├── layout.ejs ├── 403.ejs ├── 404.ejs ├── homepage.ejs └── 500.ejs └── README.md /api/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/services/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/templates/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Willkommen", 3 | "A brand new app.": "Eine neue App." 4 | } 5 | -------------------------------------------------------------------------------- /config/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Welcome", 3 | "A brand new app.": "A brand new app." 4 | } 5 | -------------------------------------------------------------------------------- /assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fraygit/SailsJs-Mysql-Association-Tutorial/HEAD/assets/favicon.ico -------------------------------------------------------------------------------- /config/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Bienvenue", 3 | "A brand new app.": "Une toute nouvelle application." 4 | } 5 | -------------------------------------------------------------------------------- /config/locales/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "Welcome": "Bienvenido", 3 | "A brand new app.": "Una aplicación de la nueva marca." 4 | } 5 | -------------------------------------------------------------------------------- /tasks/register/default.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('default', ['compileAssets', 'linkAssets', 'watch']); 3 | }; 4 | -------------------------------------------------------------------------------- /tasks/register/syncAssets.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('syncAssets', [ 3 | 'jst:dev', 4 | 'less:dev', 5 | 'sync:dev', 6 | 'coffee:dev' 7 | ]); 8 | }; 9 | -------------------------------------------------------------------------------- /tasks/register/build.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('build', [ 3 | 'compileAssets', 4 | 'linkAssetsBuild', 5 | 'clean:build', 6 | 'copy:build' 7 | ]); 8 | }; 9 | -------------------------------------------------------------------------------- /tasks/register/compileAssets.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('compileAssets', [ 3 | 'clean:dev', 4 | 'jst:dev', 5 | 'less:dev', 6 | 'copy:dev', 7 | 'coffee:dev' 8 | ]); 9 | }; 10 | -------------------------------------------------------------------------------- /tasks/register/buildProd.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('buildProd', [ 3 | 'compileAssets', 4 | 'concat', 5 | 'uglify', 6 | 'cssmin', 7 | 'linkAssetsBuildProd', 8 | 'clean:build', 9 | 'copy:build' 10 | ]); 11 | }; 12 | -------------------------------------------------------------------------------- /assets/robots.txt: -------------------------------------------------------------------------------- 1 | # The robots.txt file is used to control how search engines index your live URLs. 2 | # See http://www.robotstxt.org/wc/norobots.html for more information. 3 | 4 | 5 | 6 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 7 | # User-Agent: * 8 | # Disallow: / 9 | -------------------------------------------------------------------------------- /tasks/register/linkAssets.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('linkAssets', [ 3 | 'sails-linker:devJs', 4 | 'sails-linker:devStyles', 5 | 'sails-linker:devTpl', 6 | 'sails-linker:devJsJade', 7 | 'sails-linker:devStylesJade', 8 | 'sails-linker:devTplJade' 9 | ]); 10 | }; 11 | -------------------------------------------------------------------------------- /tasks/register/linkAssetsBuild.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('linkAssetsBuild', [ 3 | 'sails-linker:devJsRelative', 4 | 'sails-linker:devStylesRelative', 5 | 'sails-linker:devTpl', 6 | 'sails-linker:devJsRelativeJade', 7 | 'sails-linker:devStylesRelativeJade', 8 | 'sails-linker:devTplJade' 9 | ]); 10 | }; 11 | -------------------------------------------------------------------------------- /tasks/register/linkAssetsBuildProd.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('linkAssetsBuildProd', [ 3 | 'sails-linker:prodJsRelative', 4 | 'sails-linker:prodStylesRelative', 5 | 'sails-linker:devTpl', 6 | 'sails-linker:prodJsRelativeJade', 7 | 'sails-linker:prodStylesRelativeJade', 8 | 'sails-linker:devTplJade' 9 | ]); 10 | }; 11 | -------------------------------------------------------------------------------- /tasks/register/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.registerTask('prod', [ 3 | 'compileAssets', 4 | 'concat', 5 | 'uglify', 6 | 'cssmin', 7 | 'sails-linker:prodJs', 8 | 'sails-linker:prodStyles', 9 | 'sails-linker:devTpl', 10 | 'sails-linker:prodJsJade', 11 | 'sails-linker:prodStylesJade', 12 | 'sails-linker:devTplJade' 13 | ]); 14 | }; 15 | -------------------------------------------------------------------------------- /api/models/Customer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Customer.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/#!documentation/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | connection: 'someMysqlServer', 11 | 12 | attributes: { 13 | 14 | Name: { 15 | type: 'string', 16 | }, 17 | 18 | store: { 19 | model: 'Store' 20 | } 21 | 22 | } 23 | }; 24 | 25 | -------------------------------------------------------------------------------- /api/models/Driver.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Driver.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/#!documentation/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | connection: 'someMysqlServer', 11 | 12 | attributes: { 13 | Name: { 14 | type: 'string', 15 | }, 16 | 17 | car: { 18 | model: 'Car', 19 | required: false 20 | } 21 | } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /api/models/Store.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Store.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/#!documentation/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | connection: 'someMysqlServer', 11 | 12 | attributes: { 13 | name: { 14 | type: 'string' 15 | }, 16 | 17 | customers: { 18 | collection: 'Customer', 19 | via: 'store' 20 | } 21 | } 22 | }; 23 | 24 | -------------------------------------------------------------------------------- /tasks/config/clean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Clean files and folders. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * This grunt task is configured to clean out the contents in the .tmp/public of your 7 | * sails project. 8 | * 9 | * For usage docs see: 10 | * https://github.com/gruntjs/grunt-contrib-clean 11 | */ 12 | module.exports = function(grunt) { 13 | 14 | grunt.config.set('clean', { 15 | dev: ['.tmp/public/**'], 16 | build: ['www'] 17 | }); 18 | 19 | grunt.loadNpmTasks('grunt-contrib-clean'); 20 | }; 21 | -------------------------------------------------------------------------------- /tasks/config/uglify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Minify files with UglifyJS. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Minifies client-side javascript `assets`. 7 | * 8 | * For usage docs see: 9 | * https://github.com/gruntjs/grunt-contrib-uglify 10 | * 11 | */ 12 | module.exports = function(grunt) { 13 | 14 | grunt.config.set('uglify', { 15 | dist: { 16 | src: ['.tmp/public/concat/production.js'], 17 | dest: '.tmp/public/min/production.min.js' 18 | } 19 | }); 20 | 21 | grunt.loadNpmTasks('grunt-contrib-uglify'); 22 | }; 23 | -------------------------------------------------------------------------------- /tasks/config/cssmin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compress CSS files. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Minifies css files and places them into .tmp/public/min directory. 7 | * 8 | * For usage docs see: 9 | * https://github.com/gruntjs/grunt-contrib-cssmin 10 | */ 11 | module.exports = function(grunt) { 12 | 13 | grunt.config.set('cssmin', { 14 | dist: { 15 | src: ['.tmp/public/concat/production.css'], 16 | dest: '.tmp/public/min/production.min.css' 17 | } 18 | }); 19 | 20 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 21 | }; 22 | -------------------------------------------------------------------------------- /api/models/Car.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Car.js 3 | * 4 | * @description :: TODO: You might write a short summary of how this model works and what it represents here. 5 | * @docs :: http://sailsjs.org/#!documentation/models 6 | */ 7 | 8 | module.exports = { 9 | 10 | connection: 'someMysqlServer', 11 | 12 | attributes: { 13 | Name: { 14 | type: 'string', 15 | }, 16 | 17 | Brand: { 18 | type: 'string' 19 | }, 20 | 21 | Model: { 22 | type: 'string' 23 | }, 24 | 25 | driver: { 26 | model: 'Driver', 27 | required: false 28 | } 29 | } 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /config/bootstrap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap 3 | * (sails.config.bootstrap) 4 | * 5 | * An asynchronous bootstrap function that runs before your Sails app gets lifted. 6 | * This gives you an opportunity to set up your data model, run jobs, or perform some special logic. 7 | * 8 | * For more information on bootstrapping your app, check out: 9 | * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.bootstrap.html 10 | */ 11 | 12 | module.exports.bootstrap = function(cb) { 13 | 14 | // It's very important to trigger this callback method when you are finished 15 | // with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap) 16 | cb(); 17 | }; 18 | -------------------------------------------------------------------------------- /tasks/config/sync.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A grunt task to keep directories in sync. It is very similar to grunt-contrib-copy 3 | * but tries to copy only those files that has actually changed. 4 | * 5 | * --------------------------------------------------------------- 6 | * 7 | * Synchronize files from the `assets` folder to `.tmp/public`, 8 | * smashing anything that's already there. 9 | * 10 | * For usage docs see: 11 | * https://github.com/tomusdrw/grunt-sync 12 | * 13 | */ 14 | module.exports = function(grunt) { 15 | 16 | grunt.config.set('sync', { 17 | dev: { 18 | files: [{ 19 | cwd: './assets', 20 | src: ['**/*.!(coffee)'], 21 | dest: '.tmp/public' 22 | }] 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-sync'); 27 | }; 28 | -------------------------------------------------------------------------------- /api/policies/sessionAuth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sessionAuth 3 | * 4 | * @module :: Policy 5 | * @description :: Simple policy to allow any authenticated user 6 | * Assumes that your login action in one of your controllers sets `req.session.authenticated = true;` 7 | * @docs :: http://sailsjs.org/#!documentation/policies 8 | * 9 | */ 10 | module.exports = function(req, res, next) { 11 | 12 | // User is allowed, proceed to the next policy, 13 | // or if this is the last policy, the controller 14 | if (req.session.authenticated) { 15 | return next(); 16 | } 17 | 18 | // User is not allowed 19 | // (default res.forbidden() behavior can be overridden in `config/403.js`) 20 | return res.forbidden('You are not permitted to perform this action.'); 21 | }; 22 | -------------------------------------------------------------------------------- /tasks/config/less.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compiles LESS files into CSS. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Only the `assets/styles/importer.less` is compiled. 7 | * This allows you to control the ordering yourself, i.e. import your 8 | * dependencies, mixins, variables, resets, etc. before other stylesheets) 9 | * 10 | * For usage docs see: 11 | * https://github.com/gruntjs/grunt-contrib-less 12 | */ 13 | module.exports = function(grunt) { 14 | 15 | grunt.config.set('less', { 16 | dev: { 17 | files: [{ 18 | expand: true, 19 | cwd: 'assets/styles/', 20 | src: ['importer.less'], 21 | dest: '.tmp/public/styles/', 22 | ext: '.css' 23 | }] 24 | } 25 | }); 26 | 27 | grunt.loadNpmTasks('grunt-contrib-less'); 28 | }; 29 | -------------------------------------------------------------------------------- /tasks/config/concat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Concatenate files. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Concatenates files javascript and css from a defined array. Creates concatenated files in 7 | * .tmp/public/contact directory 8 | * [concat](https://github.com/gruntjs/grunt-contrib-concat) 9 | * 10 | * For usage docs see: 11 | * https://github.com/gruntjs/grunt-contrib-concat 12 | */ 13 | module.exports = function(grunt) { 14 | 15 | grunt.config.set('concat', { 16 | js: { 17 | src: require('../pipeline').jsFilesToInject, 18 | dest: '.tmp/public/concat/production.js' 19 | }, 20 | css: { 21 | src: require('../pipeline').cssFilesToInject, 22 | dest: '.tmp/public/concat/production.css' 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-contrib-concat'); 27 | }; 28 | -------------------------------------------------------------------------------- /tasks/config/watch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Run predefined tasks whenever watched file patterns are added, changed or deleted. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Watch for changes on 7 | * - files in the `assets` folder 8 | * - the `tasks/pipeline.js` file 9 | * and re-run the appropriate tasks. 10 | * 11 | * For usage docs see: 12 | * https://github.com/gruntjs/grunt-contrib-watch 13 | * 14 | */ 15 | module.exports = function(grunt) { 16 | 17 | grunt.config.set('watch', { 18 | api: { 19 | 20 | // API files to watch: 21 | files: ['api/**/*'] 22 | }, 23 | assets: { 24 | 25 | // Assets to watch: 26 | files: ['assets/**/*', 'tasks/pipeline.js'], 27 | 28 | // When assets are changed: 29 | tasks: ['syncAssets' , 'linkAssets'] 30 | } 31 | }); 32 | 33 | grunt.loadNpmTasks('grunt-contrib-watch'); 34 | }; 35 | -------------------------------------------------------------------------------- /config/env/development.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Development environment settings 3 | * 4 | * This file can include shared settings for a development team, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | /*************************************************************************** 16 | * Set the default database connection for models in the development * 17 | * environment (see config/connections.js and config/models.js ) * 18 | ***************************************************************************/ 19 | 20 | // models: { 21 | // connection: 'someMongodbServer' 22 | // } 23 | 24 | }; 25 | -------------------------------------------------------------------------------- /tasks/config/coffee.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Compile CoffeeScript files to JavaScript. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * Compiles coffeeScript files from `assest/js` into Javascript and places them into 7 | * `.tmp/public/js` directory. 8 | * 9 | * For usage docs see: 10 | * https://github.com/gruntjs/grunt-contrib-coffee 11 | */ 12 | module.exports = function(grunt) { 13 | 14 | grunt.config.set('coffee', { 15 | dev: { 16 | options: { 17 | bare: true, 18 | sourceMap: true, 19 | sourceRoot: './' 20 | }, 21 | files: [{ 22 | expand: true, 23 | cwd: 'assets/js/', 24 | src: ['**/*.coffee'], 25 | dest: '.tmp/public/js/', 26 | ext: '.js' 27 | }, { 28 | expand: true, 29 | cwd: 'assets/js/', 30 | src: ['**/*.coffee'], 31 | dest: '.tmp/public/js/', 32 | ext: '.js' 33 | }] 34 | } 35 | }); 36 | 37 | grunt.loadNpmTasks('grunt-contrib-coffee'); 38 | }; 39 | -------------------------------------------------------------------------------- /tasks/config/copy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copy files and folders. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * # dev task config 7 | * Copies all directories and files, exept coffescript and less fiels, from the sails 8 | * assets folder into the .tmp/public directory. 9 | * 10 | * # build task config 11 | * Copies all directories nd files from the .tmp/public directory into a www directory. 12 | * 13 | * For usage docs see: 14 | * https://github.com/gruntjs/grunt-contrib-copy 15 | */ 16 | module.exports = function(grunt) { 17 | 18 | grunt.config.set('copy', { 19 | dev: { 20 | files: [{ 21 | expand: true, 22 | cwd: './assets', 23 | src: ['**/*.!(coffee|less)'], 24 | dest: '.tmp/public' 25 | }] 26 | }, 27 | build: { 28 | files: [{ 29 | expand: true, 30 | cwd: '.tmp/public', 31 | src: ['**/*'], 32 | dest: 'www' 33 | }] 34 | } 35 | }); 36 | 37 | grunt.loadNpmTasks('grunt-contrib-copy'); 38 | }; 39 | -------------------------------------------------------------------------------- /assets/styles/importer.less: -------------------------------------------------------------------------------- 1 | /** 2 | * importer.less 3 | * 4 | * By default, new Sails projects are configured to compile this file 5 | * from LESS to CSS. Unlike CSS files, LESS files are not compiled and 6 | * included automatically unless they are imported below. 7 | * 8 | * The LESS files imported below are compiled and included in the order 9 | * they are listed. Mixins, variables, etc. should be imported first 10 | * so that they can be accessed by subsequent LESS stylesheets. 11 | * 12 | * (Just like the rest of the asset pipeline bundled in Sails, you can 13 | * always omit, customize, or replace this behavior with SASS, SCSS, 14 | * or any other Grunt tasks you like.) 15 | */ 16 | 17 | 18 | 19 | // For example: 20 | // 21 | // @import 'variables/colors.less'; 22 | // @import 'mixins/foo.less'; 23 | // @import 'mixins/bar.less'; 24 | // @import 'mixins/baz.less'; 25 | // 26 | // @import 'styleguide.less'; 27 | // @import 'pages/login.less'; 28 | // @import 'pages/signup.less'; 29 | // 30 | // etc. 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Tutorial", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "a Sails application", 6 | "keywords": [], 7 | "dependencies": { 8 | "sails": "~0.10.5", 9 | "sails-disk": "~0.10.0", 10 | "rc": "~0.5.0", 11 | "include-all": "~0.1.3", 12 | "ejs": "~0.8.4", 13 | "grunt": "0.4.2", 14 | "grunt-sync": "~0.0.4", 15 | "grunt-contrib-copy": "~0.5.0", 16 | "grunt-contrib-clean": "~0.5.0", 17 | "grunt-contrib-concat": "~0.3.0", 18 | "grunt-sails-linker": "~0.9.5", 19 | "grunt-contrib-jst": "~0.6.0", 20 | "grunt-contrib-watch": "~0.5.3", 21 | "grunt-contrib-uglify": "~0.4.0", 22 | "grunt-contrib-cssmin": "~0.9.0", 23 | "grunt-contrib-less": "0.11.1", 24 | "grunt-contrib-coffee": "~0.10.1" 25 | }, 26 | "scripts": { 27 | "start": "node app.js", 28 | "debug": "node debug app.js" 29 | }, 30 | "main": "app.js", 31 | "repository": { 32 | "type": "git", 33 | "url": "git://github.com/anonymous node/sails user/Tutorial.git" 34 | }, 35 | "author": "anonymous node/sails user", 36 | "license": "" 37 | } -------------------------------------------------------------------------------- /config/locales/_README.md: -------------------------------------------------------------------------------- 1 | # Internationalization / Localization Settings 2 | 3 | > Also see the official docs on internationalization/localization: 4 | > http://links.sailsjs.org/docs/config/locales 5 | 6 | ## Locales 7 | All locale files live under `config/locales`. Here is where you can add translations 8 | as JSON key-value pairs. The name of the file should match the language that you are supporting, which allows for automatic language detection based on request headers. 9 | 10 | Here is an example locale stringfile for the Spanish language (`config/locales/es.json`): 11 | ```json 12 | { 13 | "Hello!": "Hola!", 14 | "Hello %s, how are you today?": "¿Hola %s, como estas?", 15 | } 16 | ``` 17 | ## Usage 18 | Locales can be accessed in controllers/policies through `res.i18n()`, or in views through the `__(key)` or `i18n(key)` functions. 19 | Remember that the keys are case sensitive and require exact key matches, e.g. 20 | 21 | ```ejs 22 |
<%= i18n('That\'s right-- you can use either i18n() or __()') %>
25 | ``` 26 | 27 | ## Configuration 28 | Localization/internationalization config can be found in `config/i18n.js`, from where you can set your supported locales. 29 | -------------------------------------------------------------------------------- /config/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Built-in Log Configuration 3 | * (sails.config.log) 4 | * 5 | * Configure the log level for your app, as well as the transport 6 | * (Underneath the covers, Sails uses Winston for logging, which 7 | * allows for some pretty neat custom transports/adapters for log messages) 8 | * 9 | * For more information on the Sails logger, check out: 10 | * http://sailsjs.org/#/documentation/concepts/Logging 11 | */ 12 | 13 | module.exports.log = { 14 | 15 | /*************************************************************************** 16 | * * 17 | * Valid `level` configs: i.e. the minimum log level to capture with * 18 | * sails.log.*() * 19 | * * 20 | * The order of precedence for log levels from lowest to highest is: * 21 | * silly, verbose, info, debug, warn, error * 22 | * * 23 | * You may also set the level to "silent" to suppress all logs. * 24 | * * 25 | ***************************************************************************/ 26 | 27 | // level: 'info' 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /api/responses/ok.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 200 (OK) Response 3 | * 4 | * Usage: 5 | * return res.ok(); 6 | * return res.ok(data); 7 | * return res.ok(data, 'auth/login'); 8 | * 9 | * @param {Object} data 10 | * @param {String|Object} options 11 | * - pass string to render specified view 12 | */ 13 | 14 | module.exports = function sendOK (data, options) { 15 | 16 | // Get access to `req`, `res`, & `sails` 17 | var req = this.req; 18 | var res = this.res; 19 | var sails = req._sails; 20 | 21 | sails.log.silly('res.ok() :: Sending 200 ("OK") response'); 22 | 23 | // Set status code 24 | res.status(200); 25 | 26 | // If appropriate, serve data as JSON(P) 27 | if (req.wantsJSON) { 28 | return res.jsonx(data); 29 | } 30 | 31 | // If second argument is a string, we take that to mean it refers to a view. 32 | // If it was omitted, use an empty object (`{}`) 33 | options = (typeof options === 'string') ? { view: options } : options || {}; 34 | 35 | // If a view was provided in options, serve it. 36 | // Otherwise try to guess an appropriate view, or if that doesn't 37 | // work, just send JSON. 38 | if (options.view) { 39 | return res.view(options.view, { data: data }); 40 | } 41 | 42 | // If no second argument provided, try to serve the implied view, 43 | // but fall back to sending JSON(P) if no view can be inferred. 44 | else return res.guessView({ data: data }, function couldNotGuessView () { 45 | return res.jsonx(data); 46 | }); 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /tasks/config/jst.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Precompiles Underscore templates to a `.jst` file. 3 | * 4 | * --------------------------------------------------------------- 5 | * 6 | * (i.e. basically it takes HTML files and turns them into tiny little 7 | * javascript functions that you pass data to and return HTML. This can 8 | * speed up template rendering on the client, and reduce bandwidth usage.) 9 | * 10 | * For usage docs see: 11 | * https://github.com/gruntjs/grunt-contrib-jst 12 | * 13 | */ 14 | 15 | module.exports = function(grunt) { 16 | 17 | var templateFilesToInject = [ 18 | 'templates/**/*.html' 19 | ]; 20 | 21 | grunt.config.set('jst', { 22 | dev: { 23 | 24 | // To use other sorts of templates, specify a regexp like the example below: 25 | // options: { 26 | // templateSettings: { 27 | // interpolate: /\{\{(.+?)\}\}/g 28 | // } 29 | // }, 30 | 31 | // Note that the interpolate setting above is simply an example of overwriting lodash's 32 | // default interpolation. If you want to parse templates with the default _.template behavior 33 | // (i.e. using ), there's no need to overwrite `templateSettings.interpolate`. 34 | 35 | 36 | files: { 37 | // e.g. 38 | // 'relative/path/from/gruntfile/to/compiled/template/destination' : ['relative/path/to/sourcefiles/**/*.html'] 39 | '.tmp/public/jst.js': require('../pipeline').templateFilesToInject 40 | } 41 | } 42 | }); 43 | 44 | grunt.loadNpmTasks('grunt-contrib-jst'); 45 | }; 46 | -------------------------------------------------------------------------------- /api/controllers/CarController.js: -------------------------------------------------------------------------------- 1 | /** 2 | * CarController 3 | * 4 | * @description :: Server-side logic for managing Cars 5 | * @help :: See http://links.sailsjs.org/docs/controllers 6 | */ 7 | 8 | module.exports = { 9 | 10 | add: function(req, res){ 11 | var driver = {Name: 'Juan'}; 12 | Driver.create(driver).exec(function(err, result){ 13 | Car.create({ 14 | Name: 'My Car', 15 | Brand: 'Honda', 16 | Model: 'Civic', 17 | driver: result.id 18 | }).exec(function (e, r){ 19 | Driver.update({id: result.id}, {car: r.id}).exec(function(e1, r1){ 20 | return res.json({result: r, error: e}); 21 | }); 22 | }); 23 | }); 24 | }, 25 | 26 | viewCar: function(req, res){ 27 | Car.find().populate('driver').exec(function(e, r){ 28 | return res.json({Car: r}); 29 | }); 30 | }, 31 | 32 | viewDriver: function(req, res){ 33 | Driver.find().populate('car').exec(function(e, r){ 34 | return res.json({Car: r}); 35 | }); 36 | }, 37 | 38 | addStoreCustomer: function(req, res){ 39 | Store.create({Name: 'Sari Sari Store'}).exec(function(e,r){ 40 | Customer.create({Name: 'Pedro', store: r.id}).exec(function(err, result){ 41 | Customer.create({Name: 'Juan', store: r.id}).exec(function(err1, res1){ 42 | return res.json({ok: 'success'}); 43 | }); 44 | }); 45 | }); 46 | }, 47 | 48 | viewStore: function(req, res){ 49 | Store.find().populate('customers').exec(function (err, result){ 50 | res.json({Result: result}); 51 | }); 52 | } 53 | 54 | }; 55 | 56 | -------------------------------------------------------------------------------- /config/env/production.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Production environment settings 3 | * 4 | * This file can include shared settings for a production environment, 5 | * such as API keys or remote database passwords. If you're using 6 | * a version control solution for your Sails app, this file will 7 | * be committed to your repository unless you add it to your .gitignore 8 | * file. If your repository will be publicly viewable, don't add 9 | * any private information to this file! 10 | * 11 | */ 12 | 13 | module.exports = { 14 | 15 | /*************************************************************************** 16 | * Set the default database connection for models in the production * 17 | * environment (see config/connections.js and config/models.js ) * 18 | ***************************************************************************/ 19 | 20 | // models: { 21 | // connection: 'someMysqlServer' 22 | // }, 23 | 24 | /*************************************************************************** 25 | * Set the port in the production environment to 80 * 26 | ***************************************************************************/ 27 | 28 | // port: 80, 29 | 30 | /*************************************************************************** 31 | * Set the log level in production environment to "silent" * 32 | ***************************************************************************/ 33 | 34 | // log: { 35 | // level: "silent" 36 | // } 37 | 38 | }; 39 | -------------------------------------------------------------------------------- /config/models.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Default model configuration 3 | * (sails.config.models) 4 | * 5 | * Unless you override them, the following properties will be included 6 | * in each of your models. 7 | * 8 | * For more info on Sails models, see: 9 | * http://sailsjs.org/#/documentation/concepts/ORM 10 | */ 11 | 12 | module.exports.models = { 13 | 14 | /*************************************************************************** 15 | * * 16 | * Your app's default connection. i.e. the name of one of your app's * 17 | * connections (see `config/connections.js`) * 18 | * * 19 | ***************************************************************************/ 20 | // connection: 'localDiskDb', 21 | 22 | /*************************************************************************** 23 | * * 24 | * How and whether Sails will attempt to automatically rebuild the * 25 | * tables/collections/etc. in your schema. * 26 | * * 27 | * See http://sailsjs.org/#/documentation/concepts/ORM/model-settings.html * 28 | * * 29 | ***************************************************************************/ 30 | // migrate: 'alter' 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * app.js 3 | * 4 | * Use `app.js` to run your app without `sails lift`. 5 | * To start the server, run: `node app.js`. 6 | * 7 | * This is handy in situations where the sails CLI is not relevant or useful. 8 | * 9 | * For example: 10 | * => `node app.js` 11 | * => `forever start app.js` 12 | * => `node debug app.js` 13 | * => `modulus deploy` 14 | * => `heroku scale` 15 | * 16 | * 17 | * The same command-line arguments are supported, e.g.: 18 | * `node app.js --silent --port=80 --prod` 19 | */ 20 | 21 | // Ensure a "sails" can be located: 22 | (function() { 23 | var sails; 24 | try { 25 | sails = require('sails'); 26 | } catch (e) { 27 | console.error('To run an app using `node app.js`, you usually need to have a version of `sails` installed in the same directory as your app.'); 28 | console.error('To do that, run `npm install sails`'); 29 | console.error(''); 30 | console.error('Alternatively, if you have sails installed globally (i.e. you did `npm install -g sails`), you can use `sails lift`.'); 31 | console.error('When you run `sails lift`, your app will still use a local `./node_modules/sails` dependency if it exists,'); 32 | console.error('but if it doesn\'t, the app will run with the global sails instead!'); 33 | return; 34 | } 35 | 36 | // Try to get `rc` dependency 37 | var rc; 38 | try { 39 | rc = require('rc'); 40 | } catch (e0) { 41 | try { 42 | rc = require('sails/node_modules/rc'); 43 | } catch (e1) { 44 | console.error('Could not find dependency: `rc`.'); 45 | console.error('Your `.sailsrc` file(s) will be ignored.'); 46 | console.error('To resolve this, run:'); 47 | console.error('npm install rc --save'); 48 | rc = function () { return {}; }; 49 | } 50 | } 51 | 52 | 53 | // Start server 54 | sails.lift(rc('sails')); 55 | })(); 56 | -------------------------------------------------------------------------------- /api/responses/badRequest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 400 (Bad Request) Handler 3 | * 4 | * Usage: 5 | * return res.badRequest(); 6 | * return res.badRequest(data); 7 | * return res.badRequest(data, 'some/specific/badRequest/view'); 8 | * 9 | * e.g.: 10 | * ``` 11 | * return res.badRequest( 12 | * 'Please choose a valid `password` (6-12 characters)', 13 | * 'trial/signup' 14 | * ); 15 | * ``` 16 | */ 17 | 18 | module.exports = function badRequest(data, options) { 19 | 20 | // Get access to `req`, `res`, & `sails` 21 | var req = this.req; 22 | var res = this.res; 23 | var sails = req._sails; 24 | 25 | // Set status code 26 | res.status(400); 27 | 28 | // Log error to console 29 | if (data !== undefined) { 30 | sails.log.verbose('Sending 400 ("Bad Request") response: \n',data); 31 | } 32 | else sails.log.verbose('Sending 400 ("Bad Request") response'); 33 | 34 | // Only include errors in response if application environment 35 | // is not set to 'production'. In production, we shouldn't 36 | // send back any identifying information about errors. 37 | if (sails.config.environment === 'production') { 38 | data = undefined; 39 | } 40 | 41 | // If the user-agent wants JSON, always respond with JSON 42 | if (req.wantsJSON) { 43 | return res.jsonx(data); 44 | } 45 | 46 | // If second argument is a string, we take that to mean it refers to a view. 47 | // If it was omitted, use an empty object (`{}`) 48 | options = (typeof options === 'string') ? { view: options } : options || {}; 49 | 50 | // If a view was provided in options, serve it. 51 | // Otherwise try to guess an appropriate view, or if that doesn't 52 | // work, just send JSON. 53 | if (options.view) { 54 | return res.view(options.view, { data: data }); 55 | } 56 | 57 | // If no second argument provided, try to serve the implied view, 58 | // but fall back to sending JSON(P) if no view can be inferred. 59 | else return res.guessView({ data: data }, function couldNotGuessView () { 60 | return res.jsonx(data); 61 | }); 62 | 63 | }; 64 | 65 | -------------------------------------------------------------------------------- /tasks/pipeline.js: -------------------------------------------------------------------------------- 1 | /** 2 | * grunt/pipeline.js 3 | * 4 | * The order in which your css, javascript, and template files should be 5 | * compiled and linked from your views and static HTML files. 6 | * 7 | * (Note that you can take advantage of Grunt-style wildcard/glob/splat expressions 8 | * for matching multiple files.) 9 | */ 10 | 11 | 12 | 13 | // CSS files to inject in order 14 | // 15 | // (if you're using LESS with the built-in default config, you'll want 16 | // to change `assets/styles/importer.less` instead.) 17 | var cssFilesToInject = [ 18 | 'styles/**/*.css' 19 | ]; 20 | 21 | 22 | // Client-side javascript files to inject in order 23 | // (uses Grunt-style wildcard/glob/splat expressions) 24 | var jsFilesToInject = [ 25 | 26 | // Load sails.io before everything else 27 | 'js/dependencies/sails.io.js', 28 | 29 | // Dependencies like jQuery, or Angular are brought in here 30 | 'js/dependencies/**/*.js', 31 | 32 | // All of the rest of your client-side js files 33 | // will be injected here in no particular order. 34 | 'js/**/*.js' 35 | ]; 36 | 37 | 38 | // Client-side HTML templates are injected using the sources below 39 | // The ordering of these templates shouldn't matter. 40 | // (uses Grunt-style wildcard/glob/splat expressions) 41 | // 42 | // By default, Sails uses JST templates and precompiles them into 43 | // functions for you. If you want to use jade, handlebars, dust, etc., 44 | // with the linker, no problem-- you'll just want to make sure the precompiled 45 | // templates get spit out to the same file. Be sure and check out `tasks/README.md` 46 | // for information on customizing and installing new tasks. 47 | var templateFilesToInject = [ 48 | 'templates/**/*.html' 49 | ]; 50 | 51 | 52 | 53 | // Prefix relative paths to source files so they point to the proper locations 54 | // (i.e. where the other Grunt tasks spit them out, or in some cases, where 55 | // they reside in the first place) 56 | module.exports.cssFilesToInject = cssFilesToInject.map(function(path) { 57 | return '.tmp/public/' + path; 58 | }); 59 | module.exports.jsFilesToInject = jsFilesToInject.map(function(path) { 60 | return '.tmp/public/' + path; 61 | }); 62 | module.exports.templateFilesToInject = templateFilesToInject.map(function(path) { 63 | return 'assets/' + path; 64 | }); 65 | -------------------------------------------------------------------------------- /config/policies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Policy Mappings 3 | * (sails.config.policies) 4 | * 5 | * Policies are simple functions which run **before** your controllers. 6 | * You can apply one or more policies to a given controller, or protect 7 | * its actions individually. 8 | * 9 | * Any policy file (e.g. `api/policies/authenticated.js`) can be accessed 10 | * below by its filename, minus the extension, (e.g. "authenticated") 11 | * 12 | * For more information on how policies work, see: 13 | * http://sailsjs.org/#/documentation/concepts/Policies 14 | * 15 | * For more information on configuring policies, check out: 16 | * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.policies.html 17 | */ 18 | 19 | 20 | module.exports.policies = { 21 | 22 | /*************************************************************************** 23 | * * 24 | * Default policy for all controllers and actions (`true` allows public * 25 | * access) * 26 | * * 27 | ***************************************************************************/ 28 | 29 | // '*': true, 30 | 31 | /*************************************************************************** 32 | * * 33 | * Here's an example of mapping some policies to run before a controller * 34 | * and its actions * 35 | * * 36 | ***************************************************************************/ 37 | // RabbitController: { 38 | 39 | // Apply the `false` policy as the default for all of RabbitController's actions 40 | // (`false` prevents all access, which ensures that nothing bad happens to our rabbits) 41 | // '*': false, 42 | 43 | // For the action `nurture`, apply the 'isRabbitMother' policy 44 | // (this overrides `false` above) 45 | // nurture : 'isRabbitMother', 46 | 47 | // Apply the `isNiceToAnimals` AND `hasRabbitFood` policies 48 | // before letting any users feed our rabbits 49 | // feed : ['isNiceToAnimals', 'hasRabbitFood'] 50 | // } 51 | }; 52 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Gruntfile 3 | * 4 | * This Node script is executed when you run `grunt` or `sails lift`. 5 | * It's purpose is to load the Grunt tasks in your project's `tasks` 6 | * folder, and allow you to add and remove tasks as you see fit. 7 | * For more information on how this works, check out the `README.md` 8 | * file that was generated in your `tasks` folder. 9 | * 10 | * WARNING: 11 | * Unless you know what you're doing, you shouldn't change this file. 12 | * Check out the `tasks` directory instead. 13 | */ 14 | 15 | module.exports = function(grunt) { 16 | 17 | 18 | // Load the include-all library in order to require all of our grunt 19 | // configurations and task registrations dynamically. 20 | var includeAll; 21 | try { 22 | includeAll = require('include-all'); 23 | } catch (e0) { 24 | try { 25 | includeAll = require('sails/node_modules/include-all'); 26 | } 27 | catch(e1) { 28 | console.error('Could not find `include-all` module.'); 29 | console.error('Skipping grunt tasks...'); 30 | console.error('To fix this, please run:'); 31 | console.error('npm install include-all --save`'); 32 | console.error(); 33 | 34 | grunt.registerTask('default', []); 35 | return; 36 | } 37 | } 38 | 39 | 40 | /** 41 | * Loads Grunt configuration modules from the specified 42 | * relative path. These modules should export a function 43 | * that, when run, should either load/configure or register 44 | * a Grunt task. 45 | */ 46 | function loadTasks(relPath) { 47 | return includeAll({ 48 | dirname: require('path').resolve(__dirname, relPath), 49 | filter: /(.+)\.js$/ 50 | }) || {}; 51 | } 52 | 53 | /** 54 | * Invokes the function from a Grunt configuration module with 55 | * a single argument - the `grunt` object. 56 | */ 57 | function invokeConfigFn(tasks) { 58 | for (var taskName in tasks) { 59 | if (tasks.hasOwnProperty(taskName)) { 60 | tasks[taskName](grunt); 61 | } 62 | } 63 | } 64 | 65 | 66 | 67 | 68 | // Load task functions 69 | var taskConfigurations = loadTasks('./tasks/config'), 70 | registerDefinitions = loadTasks('./tasks/register'); 71 | 72 | // (ensure that a default task exists) 73 | if (!registerDefinitions.default) { 74 | registerDefinitions.default = function (grunt) { grunt.registerTask('default', []); }; 75 | } 76 | 77 | // Run task functions to configure Grunt. 78 | invokeConfigFn(taskConfigurations); 79 | invokeConfigFn(registerDefinitions); 80 | 81 | }; 82 | -------------------------------------------------------------------------------- /config/routes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Route Mappings 3 | * (sails.config.routes) 4 | * 5 | * Your routes map URLs to views and controllers. 6 | * 7 | * If Sails receives a URL that doesn't match any of the routes below, 8 | * it will check for matching files (images, scripts, stylesheets, etc.) 9 | * in your assets directory. e.g. `http://localhost:1337/images/foo.jpg` 10 | * might match an image file: `/assets/images/foo.jpg` 11 | * 12 | * Finally, if those don't match either, the default 404 handler is triggered. 13 | * See `api/responses/notFound.js` to adjust your app's 404 logic. 14 | * 15 | * Note: Sails doesn't ACTUALLY serve stuff from `assets`-- the default Gruntfile in Sails copies 16 | * flat files from `assets` to `.tmp/public`. This allows you to do things like compile LESS or 17 | * CoffeeScript for the front-end. 18 | * 19 | * For more information on configuring custom routes, check out: 20 | * http://sailsjs.org/#/documentation/concepts/Routes/RouteTargetSyntax.html 21 | */ 22 | 23 | module.exports.routes = { 24 | 25 | /*************************************************************************** 26 | * * 27 | * Make the view located at `views/homepage.ejs` (or `views/homepage.jade`, * 28 | * etc. depending on your default view engine) your home page. * 29 | * * 30 | * (Alternatively, remove this and add an `index.html` file in your * 31 | * `assets` directory) * 32 | * * 33 | ***************************************************************************/ 34 | 35 | '/': { 36 | view: 'homepage' 37 | } 38 | 39 | /*************************************************************************** 40 | * * 41 | * Custom routes here... * 42 | * * 43 | * If a request to a URL doesn't match any of the custom routes above, it * 44 | * is matched against Sails route blueprints. See `config/blueprints.js` * 45 | * for configuration options and examples. * 46 | * * 47 | ***************************************************************************/ 48 | 49 | }; 50 | -------------------------------------------------------------------------------- /api/responses/forbidden.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 403 (Forbidden) Handler 3 | * 4 | * Usage: 5 | * return res.forbidden(); 6 | * return res.forbidden(err); 7 | * return res.forbidden(err, 'some/specific/forbidden/view'); 8 | * 9 | * e.g.: 10 | * ``` 11 | * return res.forbidden('Access denied.'); 12 | * ``` 13 | */ 14 | 15 | module.exports = function forbidden (data, options) { 16 | 17 | // Get access to `req`, `res`, & `sails` 18 | var req = this.req; 19 | var res = this.res; 20 | var sails = req._sails; 21 | 22 | // Set status code 23 | res.status(403); 24 | 25 | // Log error to console 26 | if (data !== undefined) { 27 | sails.log.verbose('Sending 403 ("Forbidden") response: \n',data); 28 | } 29 | else sails.log.verbose('Sending 403 ("Forbidden") response'); 30 | 31 | // Only include errors in response if application environment 32 | // is not set to 'production'. In production, we shouldn't 33 | // send back any identifying information about errors. 34 | if (sails.config.environment === 'production') { 35 | data = undefined; 36 | } 37 | 38 | // If the user-agent wants JSON, always respond with JSON 39 | if (req.wantsJSON) { 40 | return res.jsonx(data); 41 | } 42 | 43 | // If second argument is a string, we take that to mean it refers to a view. 44 | // If it was omitted, use an empty object (`{}`) 45 | options = (typeof options === 'string') ? { view: options } : options || {}; 46 | 47 | // If a view was provided in options, serve it. 48 | // Otherwise try to guess an appropriate view, or if that doesn't 49 | // work, just send JSON. 50 | if (options.view) { 51 | return res.view(options.view, { data: data }); 52 | } 53 | 54 | // If no second argument provided, try to serve the default view, 55 | // but fall back to sending JSON(P) if any errors occur. 56 | else return res.view('403', { data: data }, function (err, html) { 57 | 58 | // If a view error occured, fall back to JSON(P). 59 | if (err) { 60 | // 61 | // Additionally: 62 | // • If the view was missing, ignore the error but provide a verbose log. 63 | if (err.code === 'E_VIEW_FAILED') { 64 | sails.log.verbose('res.forbidden() :: Could not locate view for error page (sending JSON instead). Details: ',err); 65 | } 66 | // Otherwise, if this was a more serious error, log to the console with the details. 67 | else { 68 | sails.log.warn('res.forbidden() :: When attempting to render error page view, an error occured (sending JSON instead). Details: ', err); 69 | } 70 | return res.jsonx(data); 71 | } 72 | 73 | return res.send(html); 74 | }); 75 | 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /api/responses/serverError.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 500 (Server Error) Response 3 | * 4 | * Usage: 5 | * return res.serverError(); 6 | * return res.serverError(err); 7 | * return res.serverError(err, 'some/specific/error/view'); 8 | * 9 | * NOTE: 10 | * If something throws in a policy or controller, or an internal 11 | * error is encountered, Sails will call `res.serverError()` 12 | * automatically. 13 | */ 14 | 15 | module.exports = function serverError (data, options) { 16 | 17 | // Get access to `req`, `res`, & `sails` 18 | var req = this.req; 19 | var res = this.res; 20 | var sails = req._sails; 21 | 22 | // Set status code 23 | res.status(500); 24 | 25 | // Log error to console 26 | if (data !== undefined) { 27 | sails.log.error('Sending 500 ("Server Error") response: \n',data); 28 | } 29 | else sails.log.error('Sending empty 500 ("Server Error") response'); 30 | 31 | // Only include errors in response if application environment 32 | // is not set to 'production'. In production, we shouldn't 33 | // send back any identifying information about errors. 34 | if (sails.config.environment === 'production') { 35 | data = undefined; 36 | } 37 | 38 | // If the user-agent wants JSON, always respond with JSON 39 | if (req.wantsJSON) { 40 | return res.jsonx(data); 41 | } 42 | 43 | // If second argument is a string, we take that to mean it refers to a view. 44 | // If it was omitted, use an empty object (`{}`) 45 | options = (typeof options === 'string') ? { view: options } : options || {}; 46 | 47 | // If a view was provided in options, serve it. 48 | // Otherwise try to guess an appropriate view, or if that doesn't 49 | // work, just send JSON. 50 | if (options.view) { 51 | return res.view(options.view, { data: data }); 52 | } 53 | 54 | // If no second argument provided, try to serve the default view, 55 | // but fall back to sending JSON(P) if any errors occur. 56 | else return res.view('500', { data: data }, function (err, html) { 57 | 58 | // If a view error occured, fall back to JSON(P). 59 | if (err) { 60 | // 61 | // Additionally: 62 | // • If the view was missing, ignore the error but provide a verbose log. 63 | if (err.code === 'E_VIEW_FAILED') { 64 | sails.log.verbose('res.serverError() :: Could not locate view for error page (sending JSON instead). Details: ',err); 65 | } 66 | // Otherwise, if this was a more serious error, log to the console with the details. 67 | else { 68 | sails.log.warn('res.serverError() :: When attempting to render error page view, an error occured (sending JSON instead). Details: ', err); 69 | } 70 | return res.jsonx(data); 71 | } 72 | 73 | return res.send(html); 74 | }); 75 | 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /api/responses/notFound.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 404 (Not Found) Handler 3 | * 4 | * Usage: 5 | * return res.notFound(); 6 | * return res.notFound(err); 7 | * return res.notFound(err, 'some/specific/notfound/view'); 8 | * 9 | * e.g.: 10 | * ``` 11 | * return res.notFound(); 12 | * ``` 13 | * 14 | * NOTE: 15 | * If a request doesn't match any explicit routes (i.e. `config/routes.js`) 16 | * or route blueprints (i.e. "shadow routes", Sails will call `res.notFound()` 17 | * automatically. 18 | */ 19 | 20 | module.exports = function notFound (data, options) { 21 | 22 | // Get access to `req`, `res`, & `sails` 23 | var req = this.req; 24 | var res = this.res; 25 | var sails = req._sails; 26 | 27 | // Set status code 28 | res.status(404); 29 | 30 | // Log error to console 31 | if (data !== undefined) { 32 | sails.log.verbose('Sending 404 ("Not Found") response: \n',data); 33 | } 34 | else sails.log.verbose('Sending 404 ("Not Found") response'); 35 | 36 | // Only include errors in response if application environment 37 | // is not set to 'production'. In production, we shouldn't 38 | // send back any identifying information about errors. 39 | if (sails.config.environment === 'production') { 40 | data = undefined; 41 | } 42 | 43 | // If the user-agent wants JSON, always respond with JSON 44 | if (req.wantsJSON) { 45 | return res.jsonx(data); 46 | } 47 | 48 | // If second argument is a string, we take that to mean it refers to a view. 49 | // If it was omitted, use an empty object (`{}`) 50 | options = (typeof options === 'string') ? { view: options } : options || {}; 51 | 52 | // If a view was provided in options, serve it. 53 | // Otherwise try to guess an appropriate view, or if that doesn't 54 | // work, just send JSON. 55 | if (options.view) { 56 | return res.view(options.view, { data: data }); 57 | } 58 | 59 | // If no second argument provided, try to serve the default view, 60 | // but fall back to sending JSON(P) if any errors occur. 61 | else return res.view('404', { data: data }, function (err, html) { 62 | 63 | // If a view error occured, fall back to JSON(P). 64 | if (err) { 65 | // 66 | // Additionally: 67 | // • If the view was missing, ignore the error but provide a verbose log. 68 | if (err.code === 'E_VIEW_FAILED') { 69 | sails.log.verbose('res.notFound() :: Could not locate view for error page (sending JSON instead). Details: ',err); 70 | } 71 | // Otherwise, if this was a more serious error, log to the console with the details. 72 | else { 73 | sails.log.warn('res.notFound() :: When attempting to render error page view, an error occured (sending JSON instead). Details: ', err); 74 | } 75 | return res.jsonx(data); 76 | } 77 | 78 | return res.send(html); 79 | }); 80 | 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /config/i18n.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Internationalization / Localization Settings 3 | * (sails.config.i18n) 4 | * 5 | * If your app will touch people from all over the world, i18n (or internationalization) 6 | * may be an important part of your international strategy. 7 | * 8 | * 9 | * For more informationom i18n in Sails, check out: 10 | * http://sailsjs.org/#/documentation/concepts/Internationalization 11 | * 12 | * For a complete list of i18n options, see: 13 | * https://github.com/mashpie/i18n-node#list-of-configuration-options 14 | * 15 | * 16 | */ 17 | 18 | module.exports.i18n = { 19 | 20 | /*************************************************************************** 21 | * * 22 | * Which locales are supported? * 23 | * * 24 | ***************************************************************************/ 25 | 26 | // locales: ['en', 'es', 'fr', 'de'] 27 | 28 | /**************************************************************************** 29 | * * 30 | * What is the default locale for the site? Note that this setting will be * 31 | * overridden for any request that sends an "Accept-Language" header (i.e. * 32 | * most browsers), but it's still useful if you need to localize the * 33 | * response for requests made by non-browser clients (e.g. cURL). * 34 | * * 35 | ****************************************************************************/ 36 | 37 | // defaultLocale: 'en', 38 | 39 | /**************************************************************************** 40 | * * 41 | * Automatically add new keys to locale (translation) files when they are * 42 | * encountered during a request? * 43 | * * 44 | ****************************************************************************/ 45 | 46 | // updateFiles: false, 47 | 48 | /**************************************************************************** 49 | * * 50 | * Path (relative to app root) of directory to store locale (translation) * 51 | * files in. * 52 | * * 53 | ****************************************************************************/ 54 | 55 | // localesDirectory: '/config/locales' 56 | 57 | }; 58 | -------------------------------------------------------------------------------- /config/csrf.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cross-Site Request Forgery Protection Settings 3 | * (sails.config.csrf) 4 | * 5 | * CSRF tokens are like a tracking chip. While a session tells the server that a user 6 | * "is who they say they are", a csrf token tells the server "you are where you say you are". 7 | * 8 | * When enabled, all non-GET requests to the Sails server must be accompanied by 9 | * a special token, identified as the '_csrf' parameter. 10 | * 11 | * This option protects your Sails app against cross-site request forgery (or CSRF) attacks. 12 | * A would-be attacker needs not only a user's session cookie, but also this timestamped, 13 | * secret CSRF token, which is refreshed/granted when the user visits a URL on your app's domain. 14 | * 15 | * This allows us to have certainty that our users' requests haven't been hijacked, 16 | * and that the requests they're making are intentional and legitimate. 17 | * 18 | * This token has a short-lived expiration timeline, and must be acquired by either: 19 | * 20 | * (a) For traditional view-driven web apps: 21 | * Fetching it from one of your views, where it may be accessed as 22 | * a local variable, e.g.: 23 | * 26 | * 27 | * or (b) For AJAX/Socket-heavy and/or single-page apps: 28 | * Sending a GET request to the `/csrfToken` route, where it will be returned 29 | * as JSON, e.g.: 30 | * { _csrf: 'ajg4JD(JGdajhLJALHDa' } 31 | * 32 | * 33 | * Enabling this option requires managing the token in your front-end app. 34 | * For traditional web apps, it's as easy as passing the data from a view into a form action. 35 | * In AJAX/Socket-heavy apps, just send a GET request to the /csrfToken route to get a valid token. 36 | * 37 | * For more information on CSRF, check out: 38 | * http://en.wikipedia.org/wiki/Cross-site_request_forgery 39 | * 40 | * For more information on this configuration file, including info on CSRF + CORS, see: 41 | * http://beta.sailsjs.org/#/documentation/reference/sails.config/sails.config.csrf.html 42 | * 43 | */ 44 | 45 | /**************************************************************************** 46 | * * 47 | * Enabled CSRF protection for your site? * 48 | * * 49 | ****************************************************************************/ 50 | 51 | // module.exports.csrf = false; 52 | 53 | /**************************************************************************** 54 | * * 55 | * You may also specify more fine-grained settings for CSRF, including the * 56 | * domains which are allowed to request the CSRF token via AJAX. These * 57 | * settings override the general CORS settings in your config/cors.js file. * 58 | * * 59 | ****************************************************************************/ 60 | 61 | // module.exports.csrf = { 62 | // grantTokenViaAjax: true, 63 | // origin: '' 64 | // } 65 | -------------------------------------------------------------------------------- /tasks/README.md: -------------------------------------------------------------------------------- 1 | # About the `tasks` folder 2 | 3 | The `tasks` directory is a suite of Grunt tasks and their configurations, bundled for your convenience. The Grunt integration is mainly useful for bundling front-end assets, (like stylesheets, scripts, & markup templates) but it can also be used to run all kinds of development tasks, from browserify compilation to database migrations. 4 | 5 | If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, read on! 6 | 7 | 8 | ### How does this work? 9 | 10 | The asset pipeline bundled in Sails is a set of Grunt tasks configured with conventional defaults designed to make your project more consistent and productive. 11 | 12 | The entire front-end asset workflow in Sails is completely customizable-- while it provides some suggestions out of the box, Sails makes no pretense that it can anticipate all of the needs you'll encounter building the browser-based/front-end portion of your application. Who's to say you're even building an app for a browser? 13 | 14 | 15 | 16 | ### What tasks does Sails run automatically? 17 | 18 | Sails runs some of these tasks (the ones in the `tasks/register` folder) automatically when you run certain commands. 19 | 20 | ###### `sails lift` 21 | 22 | Runs the `default` task (`tasks/register/default.js`). 23 | 24 | ###### `sails lift --prod` 25 | 26 | Runs the `prod` task (`tasks/register/prod.js`). 27 | 28 | ###### `sails www` 29 | 30 | Runs the `build` task (`tasks/register/build.js`). 31 | 32 | ###### `sails www --prod` (production) 33 | 34 | Runs the `buildProd` task (`tasks/register/buildProd.js`). 35 | 36 | 37 | ### Can I customize this for SASS, Angular, client-side Jade templates, etc? 38 | 39 | You can modify, omit, or replace any of these Grunt tasks to fit your requirements. You can also add your own Grunt tasks- just add a `someTask.js` file in the `grunt/config` directory to configure the new task, then register it with the appropriate parent task(s) (see files in `grunt/register/*.js`). 40 | 41 | 42 | ### Do I have to use Grunt? 43 | 44 | Nope! To disable Grunt integration in Sails, just delete your Gruntfile or disable the Grunt hook. 45 | 46 | 47 | ### What if I'm not building a web frontend? 48 | 49 | That's ok! A core tenant of Sails is client-agnosticism-- it's especially designed for building APIs used by all sorts of clients; native Android/iOS/Cordova, serverside SDKs, etc. 50 | 51 | You can completely disable Grunt by following the instructions above. 52 | 53 | If you still want to use Grunt for other purposes, but don't want any of the default web front-end stuff, just delete your project's `assets` folder and remove the front-end oriented tasks from the `grunt/register` and `grunt/config` folders. You can also run `sails new myCoolApi --no-frontend` to omit the `assets` folder and front-end-oriented Grunt tasks for future projects. You can also replace your `sails-generate-frontend` module with alternative community generators, or create your own. This allows `sails new` to create the boilerplate for native iOS apps, Android apps, Cordova apps, SteroidsJS apps, etc. 54 | 55 | -------------------------------------------------------------------------------- /config/globals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Global Variable Configuration 3 | * (sails.config.globals) 4 | * 5 | * Configure which global variables which will be exposed 6 | * automatically by Sails. 7 | * 8 | * For more information on configuration, check out: 9 | * http://sailsjs.org/#/documentation/reference/sails.config/sails.config.globals.html 10 | */ 11 | module.exports.globals = { 12 | 13 | /**************************************************************************** 14 | * * 15 | * Expose the lodash installed in Sails core as a global variable. If this * 16 | * is disabled, like any other node module you can always run npm install * 17 | * lodash --save, then var _ = require('lodash') at the top of any file. * 18 | * * 19 | ****************************************************************************/ 20 | 21 | // _: true, 22 | 23 | /**************************************************************************** 24 | * * 25 | * Expose the async installed in Sails core as a global variable. If this is * 26 | * disabled, like any other node module you can always run npm install async * 27 | * --save, then var async = require('async') at the top of any file. * 28 | * * 29 | ****************************************************************************/ 30 | 31 | // async: true, 32 | 33 | /**************************************************************************** 34 | * * 35 | * Expose the sails instance representing your app. If this is disabled, you * 36 | * can still get access via req._sails. * 37 | * * 38 | ****************************************************************************/ 39 | 40 | // sails: true, 41 | 42 | /**************************************************************************** 43 | * * 44 | * Expose each of your app's services as global variables (using their * 45 | * "globalId"). E.g. a service defined in api/models/NaturalLanguage.js * 46 | * would have a globalId of NaturalLanguage by default. If this is disabled, * 47 | * you can still access your services via sails.services.* * 48 | * * 49 | ****************************************************************************/ 50 | 51 | // services: true, 52 | 53 | /**************************************************************************** 54 | * * 55 | * Expose each of your app's models as global variables (using their * 56 | * "globalId"). E.g. a model defined in api/models/User.js would have a * 57 | * globalId of User by default. If this is disabled, you can still access * 58 | * your models via sails.models.*. * 59 | * * 60 | ****************************************************************************/ 61 | 62 | // models: true 63 | }; 64 | -------------------------------------------------------------------------------- /views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
50 | 64 | Why might this be happening? 65 |
66 |
71 |
72 |
50 | 64 | Why might this be happening? 65 |
66 |
71 |
72 | <%= view.pathFromApp + '.' +view.ext %>
27 | Run sails generate api user. This will create two files: a model api/models/User.js and a controllerapi/controllers/UserController.js.
28 |
38 | Run sails lift to start up your app server. If you visit http://localhost:1337/user in your browser, you'll see a WebSocket-compatible user API.
39 |
Blueprints are just the beginning. You'll probably also want to learn how to customize your app's routes, set up security policies, configure your data sources, and build custom controller actions. For more help getting started, check out the links on this page.
49 | 50 |
65 | <%- error %>
66 |
67 | <% } else { %>
68 |
69 | A team of highly trained sea bass is working on this as we speak.
70 | If the problem persists, please contact the system administrator and inform them of the time that the error occured, and anything you might have done that may have caused the error.
71 |