diff --git a/.gitignore b/.gitignore index e8e6ce6..468d7fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ # Dependency directory -node_modules \ No newline at end of file +node_modules + +.env \ No newline at end of file diff --git a/app_api/controllers/locations.js b/app_api/controllers/locations.js index 80e9066..b2c9ebd 100644 --- a/app_api/controllers/locations.js +++ b/app_api/controllers/locations.js @@ -37,7 +37,7 @@ module.exports.locationsListByDistance = function(req, res) { maxDistance: theEarth.getRadsFromDistance(maxDistance), num: 10 }; - if (!lng || !lat || !maxDistance) { + if ((!lng && lng!==0) || (!lat && lat!==0) || ! maxDistance) { console.log('locationsListByDistance missing params'); sendJSONresponse(res, 404, { "message": "lng, lat and maxDistance query parameters are all required" diff --git a/app_api/models/locations.js b/app_api/models/locations.js index 9338db2..cfe270e 100644 --- a/app_api/models/locations.js +++ b/app_api/models/locations.js @@ -1,14 +1,14 @@ var mongoose = require('mongoose'); var reviewSchema = new mongoose.Schema({ - author: String, + author: {type: String, required: true}, rating: { type: Number, required: true, min: 0, max: 5 }, - reviewText: String, + reviewText: {type: String, required: true}, createdOn: { type: Date, "default": Date.now diff --git a/app_server/controllers/locations.js b/app_server/controllers/locations.js index db8d394..1eafd87 100644 --- a/app_server/controllers/locations.js +++ b/app_server/controllers/locations.js @@ -1,92 +1,190 @@ +var request = require('request'); +var apiOptions = { + server : "http://localhost:3000" +}; +if (process.env.NODE_ENV === 'production') { + apiOptions.server = "https://getting-mean-loc8r.herokuapp.com"; +} + +var _isNumeric = function (n) { + return !isNaN(parseFloat(n)) && isFinite(n); +}; + +var _formatDistance = function (distance) { + var numDistance, unit; + if (distance && _isNumeric(distance)) { + if (distance > 1) { + numDistance = parseFloat(distance).toFixed(1); + unit = 'km'; + } else { + numDistance = parseInt(distance * 1000,10); + unit = 'm'; + } + return numDistance + unit; + } else { + return "?"; + } +}; + +var _showError = function (req, res, status) { + var title, content; + if (status === 404) { + title = "404, page not found"; + content = "Oh dear. Looks like we can't find this page. Sorry."; + } else if (status === 500) { + title = "500, internal server error"; + content = "How embarrassing. There's a problem with our server."; + } else { + title = status + ", something's gone wrong"; + content = "Something, somewhere, has gone just a little bit wrong."; + } + res.status(status); + res.render('generic-text', { + title : title, + content : content + }); +}; + +var renderHomepage = function(req, res, responseBody){ + var message; + if (!(responseBody instanceof Array)) { + message = "API lookup error"; + responseBody = []; + } else { + if (!responseBody.length) { + message = "No places found nearby"; + } + } + res.render('locations-list', { + title: 'Loc8r - find a place to work with wifi', + pageHeader: { + title: 'Loc8r', + strapline: 'Find places to work with wifi near you!' + }, + sidebar: "Looking for wifi and a seat? Loc8r helps you find places to work when out and about. Perhaps with coffee, cake or a pint? Let Loc8r help you find the place you're looking for.", + locations: responseBody, + message: message + }); +}; + /* GET 'home' page */ -module.exports.homelist = function(req, res) { - res.render('locations-list', { - title: 'Loc8r - find a place to work with wifi', - pageHeader: { - title: 'Loc8r', - strapline: 'Find places to work with wifi near you!' - }, - sidebar: "Looking for wifi and a seat? Loc8r helps you find places to work when out and about. Perhaps with coffee, cake or a pint? Let Loc8r help you find the place you're looking for.", - locations: [{ - name: 'Starcups', - address: '125 High Street, Reading, RG6 1PS', - rating: 3, - facilities: ['Hot drinks', 'Food', 'Premium wifi'], - distance: '100m' - }, { - name: 'Cafe Hero', - address: '125 High Street, Reading, RG6 1PS', - rating: 4, - facilities: ['Hot drinks', 'Food', 'Premium wifi'], - distance: '200m' - }, { - name: 'Burger Queen', - address: '125 High Street, Reading, RG6 1PS', - rating: 2, - facilities: ['Food', 'Premium wifi'], - distance: '250m' - }] - }); +module.exports.homelist = function(req, res){ + var requestOptions, path; + path = '/api/locations'; + requestOptions = { + url : apiOptions.server + path, + method : "GET", + json : {}, + qs : { + lng : -0.7992599, + lat : 51.378091, + maxDistance : 20 + } + }; + request( + requestOptions, + function(err, response, body) { + var i, data; + data = body; + if (response.statusCode === 200 && data.length) { + for (i=0; i')} .col-xs-12.col-md-3 diff --git a/app_server/views/location-review-form.jade b/app_server/views/location-review-form.jade index 5f06f61..3f327da 100644 --- a/app_server/views/location-review-form.jade +++ b/app_server/views/location-review-form.jade @@ -3,10 +3,12 @@ extends layout block content .row.page-header .col-lg-12 - h1 Review Starcups + h1= pageHeader.title .row .col-xs-12.col-md-6 - form.form-horizontal(action="/location", method="get", role="form") + form.form-horizontal(action="", method="post", role="form") + - if (error == "val") + .alert.alert-danger(role="alert") All fields required, please try again .form-group label.col-xs-10.col-sm-2.control-label(for="name") Name .col-xs-12.col-sm-10 diff --git a/app_server/views/locations-list.jade b/app_server/views/locations-list.jade index 73156d1..847f7af 100644 --- a/app_server/views/locations-list.jade +++ b/app_server/views/locations-list.jade @@ -10,11 +10,12 @@ block content small  #{pageHeader.strapline} .row .col-xs-12.col-sm-8 + .error= message .row.list-group each location in locations .col-xs-12.list-group-item h4 - a(href="/location")= location.name + a(href="/location/#{location._id}")= location.name small   +outputRating(location.rating) span.badge.pull-right.badge-default= location.distance diff --git a/package.json b/package.json index 8429aa8..0a08846 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "serve-favicon": "~2.1.3", "debug": "~2.0.0", "jade": "~1.6.0", - "mongoose": "~3.8.20" + "mongoose": "~3.8.20", + "request": "~2.51.0" } } diff --git a/public/javascripts/validation.js b/public/javascripts/validation.js new file mode 100644 index 0000000..30288d2 --- /dev/null +++ b/public/javascripts/validation.js @@ -0,0 +1,11 @@ +$('#addReview').submit(function (e) { + $('.alert.alert-danger').hide(); + if (!$('input#name').val() || !$('select#rating').val() || !$('textarea#review').val()) { + if ($('.alert.alert-danger').length) { + $('.alert.alert-danger').show(); + } else { + $(this).prepend(''); + } + return false; + } +}); \ No newline at end of file diff --git a/readme.md b/readme.md index 9d54f7a..5190aef 100644 --- a/readme.md +++ b/readme.md @@ -1,19 +1,35 @@ -Getting MEAN application code -============================= +# Getting MEAN application code -This is the code for the sample 'Loc8r' application that is built through the course of my book [Getting MEAN](http://www.manning.com/sholmes/). +This is the code for the sample 'Loc8r' application that is built through the course of my book [Getting MEAN](https://www.manning.com/books/getting-mean-with-mongo-express-angular-and-node). -Getting MEAN is published by Manning[www.manning.com/sholmes/](http://www.manning.com/sholmes/) +Getting MEAN is published by Manning, and teaches readers how to develop web applications end-to-end using the MEAN stack. -There are named branches for the various states of the code throughout the book, so far: +## The application at various stages + +There are named branches for the various states of the code throughout the book: * `master` **Chapter 3 start**: A blank Express 4.9.0 project * `chapter-03` **Chapter 3 end**: Creating and setting up a MEAN project -* `chapter-04-view` **Chapter 4 mid-point**: The data is hard coded into views +* `chapter-04-views` **Chapter 4 mid-point**: The data is hard coded into views * `chapter-04` **Chapter 4 end**: Building a static site with Node.js and Express * `chapter-05` **Chapter 5**: Building a data model with MongoDB and Mongoose * `chapter-06` **Chapter 6**: Writing a REST API: Exposing your MongoDB database to the application * `chapter-07` **Chapter 7**: Consuming a REST API: Using an API from inside Express * `chapter-08` **Chapter 8**: Adding Angular components to an Express application * `chapter-09` **Chapter 9**: Building a Single Page Application with Angular: Foundations -* `chapter-10` **Chapter 10**: Building a Single Page Application with Angular: The next level \ No newline at end of file +* `chapter-10` **Chapter 10**: Building a Single Page Application with Angular: The next level +* `chapter-11` **Chapter 11**: Authenticating users, managing sessions and securing APIs + +## Get the code + +To get the code for a specific branch: + +`$ git clone -b branch-name https://github.com/simonholmes/getting-MEAN.git` + +Then change into the folder the git clone command will create: + +`$ cd getting-MEAN` + +And finally install the dependencies: + +`npm install` \ No newline at end of file