diff --git a/.DS_Store b/.DS_Store index d52ed8e..5008ddf 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index fd4f2b0..8d4c2d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules .DS_Store +npm-debug.log \ No newline at end of file diff --git a/README.md b/README.md index 36f0367..7045d73 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,195 @@ -# FSJS-class-project +# FSJS Week 5 - Mongo!!!! -## Install NodeJS +**Outline** -- [Windows (http://blog.teamtreehouse.com/install-node-js-npm-windows)](http://blog.teamtreehouse.com/install-node-js-npm-windows) -- [Mac (http://blog.teamtreehouse.com/install-node-js-npm-mac)](http://blog.teamtreehouse.com/install-node-js-npm-mac) -- [Linux (http://blog.teamtreehouse.com/install-node-js-npm-linux)](http://blog.teamtreehouse.com/install-node-js-npm-linux) +2. Set up Mongo (Go ahead and start on this) +1. Set up for week5 +3. Create a model and seed it with data +4. Connect Mongo to our application + +## 1. Set up Mongo + +### Option 1 - Create a database at mLab (recommended) + +1. Head over to [mLab](https://mlab.com) (https://mlab.com) +2. If you have an account, log in, otherwise click on "Sign Up" +3. Click on "Create New" + * Any cloud provider will do + * Make sure you choose the "Sandbox" plan type + * Click "Continue" at the bottom of the page + * Answer all remaining questions (region, etc.) + * Choose a name...could be anything...maybe "fsjs-class-project" + * Complete setup +4. Click on your new database in the list and note the connection links provided +5. You will see an alert box saying "A database user is required to connect to this database." - so under the "Users" tab click the "Add database user" (you can use your mLab login information if you wish) **This will be the username and password we use later in the code** + +### Option 2 - Install mongo on your machine + +**Windows**: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/ + +**Linux** + https://docs.mongodb.com/manual/administration/install-on-linux/ + +**OSX** + https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/ + + +## 2. Setup Project +1. Clear changes made last week +``` +git reset --hard HEAD +``` + +2. Check out a clean week5 +``` +git fetch +git checkout -fb week5 origin/week5 +git pull +npm install +``` + +3. Install mongoose +``` +npm install mongoose --save +``` +**Mongoose Documentation:** http://mongoosejs.com/docs/api.html + +## HOLD THE PHONE... +**What is Mongo? Sounds like a cartoon character's name...** + +Mongo is a database. It is a place to store structured data so that your application can quickly and easily find it later. Mongo is known as a no-SQL database. In the case of Mongo, that means that it stores data in units called `documents` - which look just like javascript objects (key-value pairs, nested objects, arrays, etc.). + +## WAIT A MINUTE.... +**What is this `mongoose` of which you speak?** + +Mongoose is an ORM (Object Relational Mapping) tool. It is used in your application to make the process of querying, inserting, updating, and deleting data in a Mongo database. In addition, it turns the plain ol' javascript objects you get back from Mongo in to more feature-rich objects for your application to use. + +![Mongoose Diagram](mongoose_diag.png) + + +## Create a model using mongoose + +**In a nutshell, we will:** +1. Tell mongoose how to talk to the mongo server +2. Make sure mongoose connects to mongo when your application starts. +3. Create a "model" in mongoose. This is where you define what your data looks like. +4. Use Mongo in our route handlers instead of the array we've been using. +5. Add some test data. + + +### Configure our app to work with mongo +1. Edit our config file (at `src/config/index.js`) so that the returned configuration object includes mongo configuration: + ```javascript + module.exports = { + appName: 'Our Glorious Node Project', + port: 3030, + db: { + username: , + password: , + host: 'ds159507.mlab.com:59507', + dbName: 'fsjs-class-project', + } + }; + ``` + +2. Connect to mongo through the mongoose library. In `src/server.js`, somewhere near the top of the file, import mongoose with the following. Note that when we connect to the mongo server, we are piecing together the connection string handed to us by mLab. + ```javascript + // Load mongoose package + const mongoose = require('mongoose'); + ``` + Then, somewhere AFTER the line where you load your configuration, connect with the following + ```javascript + // Connect to MongoDB and create/use database as configured + mongoose.connection.openUri(`mongodb://${config.db.username}:${config.db.password}@${config.db.host}/${config.db.dbName}`); + ``` + + +### Build the model + +1. In the `src/models` directory, create an empty file called `file.model.js` +2. At the top of that file, pull in mongoose + ```javascript + // Load mongoose package + const mongoose = require('mongoose'); + ``` + +3. Create a schema + ```javascript + const FileSchema = new mongoose.Schema({ + title: String, + description: String, + created_at: { type: Date, default: Date.now }, + }); + ``` + Notice that the `title` and `description` fields are also present in our faked data (`/src/routes/index.js`). We've also added a new field called `created_at`, which will be a Date and will default to the current time. + +4. Turn that schema in to a mongoose model, register it, and export it + ```javascript + const File = mongoose.model('File', FileSchema); + module.exports = File; + ``` + A lot is going on here. We are storing the `File` schema inside the mongoose object (which will make it available anywhere in your application). We're also giving a name ("File") so we can distinguish it from any other model we may want to register. We're also exporting the model from this module. + +5. Make sure that the `file.model.js` script is run by `require`-ing it somewhere...like in `src/server.js`, below the line where we connect mongoose to mongo: + ```javascript + // Import all models + require('./models/file.model.js'); + ``` + +## Connect to our app +1. In `src/routes/index.js`, pull in mongoose at the top of the file. + ```javascript + const mongoose = require('mongoose'); + ``` + +2. Edit the `GET /file` route. Replace our development code with + ```javascript + mongoose.model('File').find({}, function(err, files) { + if (err) { + console.log(err); + return res.status(500).json(err); + } + + res.json(files); + }); + ``` + **Model.find:** http://mongoosejs.com/docs/api.html#model_Model.find + +3. Restart server and test - **Where did our data go?** + +### What about some test data? +Strategy: On startup, check if there are any files in the database, if not, then add files from a seed file. + +1. Create a file in `/src/models` called `file.seed.json` + ```json + [ + {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, + {"title":"Rules of Cribbage.doc", "description": "9th edition" }, + {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } + ] + ``` + +2. In `file.model.js`, after you create and export the model, get the current count of documents in the collection + ```javascript + File.count({}, function(err, count) { + if (err) { + throw err; + } + // ... + }); + ``` + **Model.count:** http://mongoosejs.com/docs/api.html#model_Model.count + +3. Add the seed data + ```javascript + if (count > 0) return ; + + const files = require('./file.seed.json'); + File.create(files, function(err, newFiles) { + if (err) { + throw err; + } + console.log("DB seeded") + }); + ``` + **Model.create:** http://mongoosejs.com/docs/api.html#model_Model.create diff --git a/week5/mongoose_diag.png b/mongoose_diag.png similarity index 100% rename from week5/mongoose_diag.png rename to mongoose_diag.png diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..53bf028 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,362 @@ +{ + "name": "fsjs-class-project", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/package.json b/package.json index 2df23f9..5e01f12 100644 --- a/package.json +++ b/package.json @@ -4,11 +4,13 @@ "description": "## Install NodeJS", "main": "index.js", "dependencies": { + "body-parser": "^1.18.2", "express": "^4.16.2" }, "devDependencies": {}, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "nodemon src/server.js" }, "repository": { "type": "git", diff --git a/week5/public/index.html b/public/index.html similarity index 60% rename from week5/public/index.html rename to public/index.html index c45aa5a..972d9d1 100644 --- a/week5/public/index.html +++ b/public/index.html @@ -4,11 +4,13 @@ Our Glorious Node Project - -

A wild webpage appears...

-
+
+

A wild webpage appears...

+ +
+
- + - - + \ No newline at end of file diff --git a/week5/public/js/app.js b/public/js/app.js similarity index 82% rename from week5/public/js/app.js rename to public/js/app.js index 6e02ca1..3c65e09 100644 --- a/week5/public/js/app.js +++ b/public/js/app.js @@ -1,5 +1,4 @@ - function getFiles() { return $.ajax('/api/file') .then(res => { @@ -7,12 +6,11 @@ function getFiles() { return res; }) .fail(err => { - console.log("Error in getFiles()", err); + console.error("Error in getFiles()", err); throw err; }); } - function refreshFileList() { const template = $('#list-template').html(); const compiledTemplate = Handlebars.compile(template); @@ -21,6 +19,10 @@ function refreshFileList() { .then(files => { const data = {files: files}; const html = compiledTemplate(data); + console.log('our html', html); $('#list-container').html(html); }) } + + +refreshFileList(); diff --git a/week2/src/config/index.js b/src/config/index.js similarity index 97% rename from week2/src/config/index.js rename to src/config/index.js index 1df2c5f..606778f 100644 --- a/week2/src/config/index.js +++ b/src/config/index.js @@ -3,4 +3,4 @@ module.exports = { appName: 'Our Glorious Node Project', port: 3030 -} +} \ No newline at end of file diff --git a/week1/src/models/index.js b/src/models/index.js similarity index 100% rename from week1/src/models/index.js rename to src/models/index.js diff --git a/week4/src/routes/index.js b/src/routes/index.js similarity index 82% rename from week4/src/routes/index.js rename to src/routes/index.js index fa8503e..0aac3c6 100644 --- a/week4/src/routes/index.js +++ b/src/routes/index.js @@ -1,6 +1,7 @@ // src/routes/index.js const router = require('express').Router(); +// Totally fake data const FILES = [ {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, @@ -13,11 +14,31 @@ router.use('/doc', function(req, res, next) { res.end(`Documentation http://expressjs.com/`); }); +/** + * Get a list of all files in the DB + */ router.get('/file', function(req, res, next) { res.json(FILES); }); +/** + * Get a single file by passing its id as a URL param + */ +router.get('/file/:fileId', function(req, res, next) { + const {fileId} = req.params; + // same as 'const fileId = req.params.fileId' + + const file = FILES.find(entry => entry.id === fileId); + if (!file) { + return res.status(404).end(`Could not find file '${fileId}'`); + } + res.json(file); +}); + +/** + * Create a new file + */ router.post('/file', function(req, res, next) { const newId = '' + FILES.length; const data = req.body; @@ -27,32 +48,20 @@ router.post('/file', function(req, res, next) { res.status(201).json(data); }); +/** + * Update an existing file + */ router.put('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - file.title = req.body.title; - file.description = req.body.description; - res.json(file); + res.end(`Updating file '${req.params.fileId}'`); }); +/** + * Delete a file + */ router.delete('/file/:fileId', function(req, res, next) { res.end(`Deleting file '${req.params.fileId}'`); }); -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); module.exports = router; + diff --git a/week4/src/server.js b/src/server.js similarity index 100% rename from week4/src/server.js rename to src/server.js index d7430e5..f376394 100644 --- a/week4/src/server.js +++ b/src/server.js @@ -1,15 +1,15 @@ // src/server.js -const path = require('path'); -const bodyParser = require('body-parser'); +const path = require('path'); const express = require('express'); +const bodyParser = require('body-parser'); const config = require('./config'); const router = require('./routes'); const app = express(); const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); app.use(bodyParser.json()); +app.use(express.static(publicPath)); app.use('/api', router); diff --git a/week1/index.js b/week1/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week1/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week1/package.json b/week1/package.json deleted file mode 100644 index bac8df4..0000000 --- a/week1/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "express": "^4.14.0" - } -} diff --git a/week1/readme.md b/week1/readme.md deleted file mode 100644 index 1f648b3..0000000 --- a/week1/readme.md +++ /dev/null @@ -1,156 +0,0 @@ -# FSJS Week 1 - Our Glorious Node Project - -**Outline** - -* Install NodeJS -* Set up the project -* npm init -* Install core packages -* Organize the project -* "Hello World" web server - -## Install NodeJS - -- [Windows (http://blog.teamtreehouse.com/install-node-js-npm-windows)](http://blog.teamtreehouse.com/install-node-js-npm-windows) -- [Mac (http://blog.teamtreehouse.com/install-node-js-npm-mac)](http://blog.teamtreehouse.com/install-node-js-npm-mac) -- [Linux (http://blog.teamtreehouse.com/install-node-js-npm-linux)](http://blog.teamtreehouse.com/install-node-js-npm-linux) - -## Set up the project -1. Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - -2. Get rid of `week1` (we're going to rebuild it) -``` -rm -rf week1 -``` - -## Start a project with `npm init` - -Starting a project in node is simple: -``` -mkdir week1 -cd week1 -npm init -``` - -`npm init` simply creates a `package.json` file a populates it with the answers to some questions. You can edit it in a text editor. - - -## Install code packages - -First, take a look at `package.json`, then run this command: -``` -npm install express --save -``` - -Now, go back to `package.json` and look at the 'dependencies' section. -Also, a new directory has appeared: `node_modules` - -The above command tells `npm` to download the [express](https://expressjs.com/) package, save it in a newly created `node_modules` directory, and then add a line in `package.json` to make note of the fact that we need 'express' for this project (that's what the `--save` part does). - - -## Organize this thing - -When starting a project, a good practice is to lay out your directory structure and create some empty, basic files: -``` -. -├── package.json -└── src - ├── config // application configuration - │   └── index.js - ├── models // Database models - │   └── index.js - ├── routes // HTTP(S) routing/controllers - │   └── index.js - └── server.js // Set up server and listen on port -``` - -## Hello World - -Open `src/config/index.js` -```javascript -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030 -} -``` - -Open `src/server.js` -Pull in some needed modules -```javascript -// src/server.js - -const express = require('express'); -const config = require('./config'); -``` - -Create our application object -```javascript -const app = express(); -``` - -Tell it what to do -```javascript -app.use(function(req, res, next) { - res.end("Hello World!"); -}); -``` - -Start the server -```javascript -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); -``` - -On the command line: -``` -node src/server.js -``` - - -Test it out by going to `http://localhost:3030` in your browser. - -Now, mix it up a bit. Put this code **BEFORE** the other `app.use` bit. -```javascript -app.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); -``` - -Visit `http://localhost:3030/doc` -Move the `/doc` route below the original `app.use` code and refresh. What happened? - -## Bonus material - -### require() is a big deal -Yes it is. The full documentation for require() (really, for Node modules in general) can be found [here (https://nodejs.org/api/modules.html)](https://nodejs.org/api/modules.html). - -`require()` is what allows you to organize your code in to easy-to-understand (hopefully) directories and files, but join them all together in to a single application. - -For comparison: in a browser environment, if you want to make content from multiple file available to the larger application you can 1) concatenate them all in to one file or 2) load them individually via a ` - - - - - - - diff --git a/week2/readme.md b/week2/readme.md deleted file mode 100644 index facbaf3..0000000 --- a/week2/readme.md +++ /dev/null @@ -1,150 +0,0 @@ -# FSJS Week 2 - Our Superlative Web Page - -**Outline** - -* Set up the project for the front end -* Serve a static page -* Add a template engine - -## Set up the project -_It should still be setup from [week 1](../week1)_ - -1. Clean the project -_If you did something you want to keep, last week, you can make a branch and commit, or copy those files out. To continue here, we are going to reset `week1` back to our code_ -``` -cd FSJS-class-project -git status -git reset --hard HEAD -git pull -``` - -2. Get rid of `week2` _(we're going to rebuild it)_ -``` -rm -rf week2 -``` - -3. Copy `week1` to `week2` _(this is our starting point)_ -``` -cp -R week1 week2 -cd week2 -``` - -4. Install dependencies -``` -npm install -``` - -## Serve a static page -1. Create a "public" directory inside the `src` directory -``` -mkdir public -``` - -2. Set up our express application to serve static files. -Add a reference to Node's `path` module to the top of the page in the `server.js` -```javascript -const path = require('path'); -``` -[[Documentation for path](https://nodejs.org/api/path.html)] - -Then add the following line to `server.js` BEFORE any routes -```javascript -const publicPath = path.resolve(__dirname, './public'); -app.use(express.static(publicPath)); -``` -[[Documentation for Node Modules (dirname)](https://nodejs.org/api/modules.html)] -[[Guide for ExpresJS static](https://expressjs.com/en/starter/static-files.html)] - -`express.static()` will search the `public` directory for a file that matches the requested path. For example: `index.html`, `img/puppy.jpg`, etc. If there is a match, that file is streamed back to the requester, otherwise, express moves on to the next route. - -3. Add an `index.html` to the public folder. -```html - - - - - Our Glorious Node Project - - -

A wild webpage appears...

- - - -``` - -4. Start the server and check that you can access a static `html` page - -Note: We previously had a "Hello World" endpoint that was served when user's requested the path `/`. That path is now unreachable, because all requests for `/` will receive `index.html`. - -`/doc` still works, though. - - -## Add a template engine -1. We'll be using jQuery and Handlebars, so let's add them to our `index.html` at the end of the `` tag -```html - - -``` -[[Documentation for jQuery](https://api.jquery.com/)] -[[Documentation for Handlebars](http://handlebarsjs.com/reference.html)] - -2. Drop a quick template in `index.html` to see how handlebars renders content: -```html - -``` - -3. Render a list of fake data. Start by adding a place in the html to render the list after the `

`: -```html -
-``` - -4. Create some fake data in another script tag -```html - -``` - -5. Create a template for each list item. -```html - -``` - -6. Right below the `list` array, compile the template and render it into the container. -```javascript -const template = $('#list-template').html(); -const compiled = Handlebars.compile(template); -$('#list-container').html(compiled(data)); -``` - -7. Refresh the page - -8. Add some style in the `` -```html - -``` diff --git a/week2/src/models/index.js b/week2/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week2/src/routes/index.js b/week2/src/routes/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week2/src/server.js b/week2/src/server.js deleted file mode 100644 index 0db3b73..0000000 --- a/week2/src/server.js +++ /dev/null @@ -1,21 +0,0 @@ -// src/server.js -const path = require('path'); - -const express = require('express'); -const config = require('./config'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); - -app.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -app.use(function(req, res, next) { - res.end("Hello World!"); -}); - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week2/src/tester/index.html b/week2/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week2/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week3/index.js b/week3/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week3/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week3/package.json b/week3/package.json deleted file mode 100644 index 05b7b92..0000000 --- a/week3/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "express": "^4.14.0" - } -} diff --git a/week3/public/index.html b/week3/public/index.html deleted file mode 100644 index 378cfe6..0000000 --- a/week3/public/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - Our Glorious Node Project - - - - -

A wild webpage appears...

-
- - - - - - - - - diff --git a/week3/readme.md b/week3/readme.md deleted file mode 100644 index bc06695..0000000 --- a/week3/readme.md +++ /dev/null @@ -1,181 +0,0 @@ -# FSJS Week 3 - A Wild Router Appears - -**Outline** - -* Set up the project -* Grab some DevTools -* The 5 operation of CRUD (list, detail, create, update, delete) -* Send mock, static data as response - - -## Set up the project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - -2. Get rid of `week3` (we're going to rebuild it) -``` -rm -rf week3 -``` - -3. Copy `week2` to `week3` -``` -cp -R week2 week3 -cd week3 -``` - -4. Install dependencies -``` -npm install -``` -## Hooray! New DevTools! - -### Postman - -Postman allows you to send HTTP requests to your API. You can tailor the url, method, payload, querystring, and headers. This is a very powerful API testing tool which will make our development easier. - -[[Download here](https://www.getpostman.com/docs/postman/launching_postman/installation_and_updates)] - -### Nodemon - -Tired of restarting your Node server every time you change a file? Hand getting a cramp from hitting `ctrl-c` after every typo fix? **You're in luck** - -Enter: Nodemon - Monitor for any changes in your node.js application and automatically restart the server - perfect for development. - -``` -npm install nodemon -g -``` - -Here, we're NOT using the `--save` switch, but we are using the mysterious `-g`. `-g` tells npm to install Nodemon globally (so it will be available for all your projects). Therefore, we don't need to save it to our `package.json` file. - -Next, add a script to `package.json`. Find the `scripts` section and replace it with the following: -```javascript -"scripts": { - "start": "nodemon index.js" -}, -``` -[[Documentation on NPM scripts](https://docs.npmjs.com/misc/scripts)] - -To start our server, type: -``` -npm start -``` - -Now, when we make changes to files, the server restarts automatically. Try it out! - -## The 5 Operations of CRUD - -| Operation | Suggested HTTP | Data | -| --- | --- | --- | -| Create | POST | Create a new element | -| Read | GET | Get a single element | -| Update | PUT | Replace an element with new data | -| Delete | DELETE | Delete a single element | -| List | GET | Get an array of elements | - -1. Do a little clean-up by moving our endpoints to a separate file. Add the following to `routes/index.js` -```javascript -// src/routes/index.js -const router = require('express').Router(); -``` -[[ExpressJS Router documentation](https://expressjs.com/en/4x/api.html#router)] - -A router object allows us to create an isolated bundle of endpoints and middleware. This is not new functionality, just a convenient way to package code in to separate, easy-to-read and easy-to-maintain files. - -Now, move our existing routes over from `server.js`: -```javascript -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -module.exports = router; -``` -(Note that our "Hello world" route is unnecessary since we are serving a static index.html) - -Now, head back to `server.js` and make sure our app knows how to use the router. Create a variable for our router at the top of the file: -```javascript -const router = require('./routes'); -``` -And then direct our app to use the router AFTER the line where we handle static files: -```javascript -app.use(express.static(publicPath)); -app.use('/api', router); -``` - -What does the `'/api'` part do? [`app.use()` Documentation here](https://expressjs.com/en/4x/api.html#app.use). Basically, this prepends `/api` to all the paths defined in `router` (currently, we only have `/doc`). So, instead of making a GET request to `/doc`, we will now make a request to `/api/doc`. - -**Fire up postman and try it** - -2. Add some basic **List** and **Create** handlers to `routes\index.js`: -```javascript -router.get('/file', function(req, res, next) { - res.end('List all files'); -}); - -router.post('/file', function(req, res, next) { - res.end('Create a new file'); -}); -``` -[[Documentation for router.get() and router.post()](https://expressjs.com/en/4x/api.html#router.METHOD)] - -Head over to postman and test it out. - -3. Add **Update**, **Delete**, and **Read** endpoints - all of which take a route parameter: -```javascript -router.put('/file/:fileId', function(req, res, next) { - res.end(`Updating file '${req.params.fileId}'`); -}); - -router.delete('/file/:fileId', function(req, res, next) { - res.end(`Deleting file '${req.params.fileId}'`); -}); - -router.get('/file/:fileId', function(req, res, next) { - res.end(`Reading file '${req.params.fileId}'`); -}); -``` -[[Documentation for Route Parameters](https://expressjs.com/en/guide/routing.html#route-parameters)] - -Route parameters allow you to pass information to the router via the url itself. When express finds a route parameter (indicated by `:`), it creates a property on `req.params` with the same name. - -## Return some data - -1. Let's add a static array of "file" object for testing purposes. Near the top of the `routes/index.js` file, add the following: -```javascript -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; -``` - -2. Return the entire list as JSON. Replace the handler for `GET /file`, with: -```javascript -router.get('/file', function(req, res, next) { - res.json(FILES); -}); -``` -[[Documentation for res.json()](https://expressjs.com/en/4x/api.html#res.json)] - -`res.json()` accepts any type of data, stringifies with `JSON.stringify()` and sends the response with the header `Content-Type: application/json`. - -3. Return a single element by replacing the handler for `GET /file/:fileId` with: -```javascript -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); -``` -[[Documentation for object destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring)] -[[Documentation for Array.prototype.find()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find?v=example)] -[[Documentation for res.status()](https://expressjs.com/en/4x/api.html#res.status)] diff --git a/week3/src/config/index.js b/week3/src/config/index.js deleted file mode 100644 index 1df2c5f..0000000 --- a/week3/src/config/index.js +++ /dev/null @@ -1,6 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030 -} diff --git a/week3/src/models/index.js b/week3/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week3/src/routes/index.js b/week3/src/routes/index.js deleted file mode 100644 index 84d461c..0000000 --- a/week3/src/routes/index.js +++ /dev/null @@ -1,45 +0,0 @@ -// src/routes/index.js -const router = require('express').Router(); - -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; - - -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -router.get('/file', function(req, res, next) { - res.json(FILES); -}); - - -router.post('/file', function(req, res, next) { - res.end('Create a new file'); -}); - -router.put('/file/:fileId', function(req, res, next) { - res.end(`Updating file '${req.params.fileId}'`); -}); - -router.delete('/file/:fileId', function(req, res, next) { - res.end(`Deleting file '${req.params.fileId}'`); -}); - -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); - -module.exports = router; diff --git a/week3/src/server.js b/week3/src/server.js deleted file mode 100644 index 032d8a4..0000000 --- a/week3/src/server.js +++ /dev/null @@ -1,16 +0,0 @@ -// src/server.js -const path = require('path'); - -const express = require('express'); -const config = require('./config'); -const router = require('./routes'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); -app.use('/api', router); - - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week3/src/tester/index.html b/week3/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week3/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week4/index.js b/week4/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week4/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week4/package.json b/week4/package.json deleted file mode 100644 index c943a5c..0000000 --- a/week4/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "body-parser": "^1.17.2", - "express": "^4.14.0" - } -} diff --git a/week4/public/index.html b/week4/public/index.html deleted file mode 100644 index c45aa5a..0000000 --- a/week4/public/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Our Glorious Node Project - - - - -

A wild webpage appears...

-
- - - - - - - - - diff --git a/week4/public/js/app.js b/week4/public/js/app.js deleted file mode 100644 index 6e02ca1..0000000 --- a/week4/public/js/app.js +++ /dev/null @@ -1,26 +0,0 @@ - - -function getFiles() { - return $.ajax('/api/file') - .then(res => { - console.log("Results from getFiles()", res); - return res; - }) - .fail(err => { - console.log("Error in getFiles()", err); - throw err; - }); -} - - -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} diff --git a/week4/readme.md b/week4/readme.md deleted file mode 100644 index 454ca97..0000000 --- a/week4/readme.md +++ /dev/null @@ -1,155 +0,0 @@ -# FSJS Week 4 - The Full Stackey - -**Outline** - -* Set up the project -* Render data from the server on our page -* Add POST and PUT endpoints - - -## Set up the project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - -**OR** if you need to ditch your current changes and pull a fresh copy down, try this: -``` -git stash -git pull -``` - -2. Get rid of `week4` (we're going to rebuild it) -``` -rm -rf week4 -``` - -3. Copy `week3` to `week4` -``` -cp -R week3 week4 -cd week4 -``` - -4. Install dependencies -``` -npm install -``` - -## Render data from the server -We have a nice API endpoint to spit out data (albeit static data from an array). Let's use that in our front-end. - -1. Create a new file in a new directory: `public\js\app.js`. -(We could continue to put all our javascript in `script` tags in `index.html`, but placing this code in a separate file will help keep things neat and organized) - -2. Load this in to our `index.html`. At the bottom of the file, just below the `script` tag that loads the handlebars library, add: -```html - -``` - -3. Update our handlebars template to render a file and not a BTVS character list. Replace the `#list-template` script in `index.html` with the following: -```html - -``` -While we're at it, we can let's delete the code that rendered our previous test data. (If you want to keep it around for reference, just comment it out.) - -4. In `app.js`, create a function to get the file list: -```javascript -function getFiles() { - return $.ajax('/api/file') - .then(res => { - console.log("Results from getFiles()", res); - return res; - }) - .fail(err => { - console.log("Error in getFiles()", err); - throw err; - }); -} -``` - -5. Create a function to refresh the list -```javascript -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} -``` -Test it out by refreshing the page, opening a debugging console, and typing `refreshFileList()`; - -6. Refresh the list automatically when the page first loads by adding `refreshFileList()` to the remaining `$().ready()` function in `index.html` - -## Finish What we started -1. We are going to be sending data from the client back to the server. To do that, we will convert a plain JS object to a JSON-formatted string (really, jQuery will do that for us). We need to set up our express server to parse that JSON string and turn it back in to an object. - -Fortunately, there a library for that: -``` -npm install body-parser --save -``` -[[Documentation for body-parser](https://github.com/expressjs/body-parser)] - -`body-parser` will look at the body of a request and, if the `Content-Type` is `application/json`, will parse the body using `JSON.parse()`. The results of that (if successful) will be put in `req.body` for use by any middleware. - -2. At the top of `server.js`, require the body-parser module: -```javascript -const bodyParser = require('body-parser'); -``` - -3. Tell our server to use it. In `server.js`, right AFTER we set up static files serving, add the following: -```javascript -app.use(function(req, res, next) { - console.log("req.body BEFORE parsing", req.body); - next(); -}) - -app.use(bodyParser.json()); - -app.use(function(req, res, next) { - console.log("req.body AFTER parsing", req.body); - next(); -}) -``` -Head over to postman. Create a POST request to ANY endpoint. Tell postman that the content is JSON (use the dropdown). Type in any valid JSON-formatted string and hit send. You'll see the contents outputted by the two middleware we added before and after the bodyParser middleware. - -4. Delete the logging middleware - -5. Go back to our routes and add the POST and PUT endpoints. In `routes/index.js`, swap out the `router.put()` and `router.post()` callbacks (which were just placeholders) with the following: -```javascript -router.post('/file', function(req, res, next) { - const newId = '' + FILES.length; - const data = req.body; - data.id = newId; - - FILES.push(data); - res.status(201).json(data); -}); -``` -and -```javascript -router.put('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - file.title = req.body.title; - file.description = req.body.description; - res.json(file); -}); -``` diff --git a/week4/src/config/index.js b/week4/src/config/index.js deleted file mode 100644 index 1df2c5f..0000000 --- a/week4/src/config/index.js +++ /dev/null @@ -1,6 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030 -} diff --git a/week4/src/models/index.js b/week4/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week4/src/tester/index.html b/week4/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week4/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week5/index.js b/week5/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week5/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week5/package.json b/week5/package.json deleted file mode 100644 index 3117c53..0000000 --- a/week5/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "body-parser": "^1.17.2", - "express": "^4.14.0", - "mongoose": "^4.10.4" - } -} diff --git a/week5/readme.md b/week5/readme.md deleted file mode 100644 index 79c38ed..0000000 --- a/week5/readme.md +++ /dev/null @@ -1,191 +0,0 @@ -# FSJS Week 5 - Mongo!!!! - -**Outline** - -2. Install Mongo (Go ahead and start on this) -1. Set up for week5 -3. Create a model and seed it with data -4. Connect Mongo to our application - -## 1. Install Mongo -**Windows**: https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/ - -**Linux** - https://docs.mongodb.com/manual/administration/install-on-linux/ - -**OSX** - https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/ - - -## 2. Setup Project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - -**OR** if you need to ditch your current changes and pull a fresh copy down, try this: -``` -git stash -git pull -``` - -2. Get rid of `week5` (we're going to rebuild it) -``` -rm -rf week5 -``` - -3. Copy `week4` to `week5` -``` -cp -R week4 week5 -cd week5 -``` - -4. Install dependencies -``` -npm install -``` - -5. Install mongoose -``` -npm install mongoose --save -``` -**Mongoose Documentation:** http://mongoosejs.com/docs/api.html - -## HOLD THE PHONE... -**What is Mongo? Sounds like a cartoon character's name...** - -Mongo is a database. It is a place to store structured data so that your application can quickly and easily find it later. Mongo is known as a no-SQL database. In the case of Mongo, that means that it stores data in units called `documents` - which look just like javascript objects (key-value pairs, nested objects, arrays, etc.). - -## WAIT A MINUTE.... -**What is this `mongoose` of which you speak?** - -Mongoose is an ORM (Object Relational Mapping) tool. It is used in your application to make the process of querying, inserting, updating, and deleting data in a Mongo database. In addition, it turns the plain ol' javascript objects you get back from Mongo in to more feature-rich objects for your application to use. - -![Mongoose Diagram](mongoose_diag.png) - - -## Create a model using mongoose - -**In a nutshell, we will:** -1. Tell mongoose how to talk to the mongo server -2. Make sure mongoose connects to mongo when your application starts. -3. Create a "model" in mongoose. This is where you define what your data looks like. -4. Use Mongo in our route handlers instead of the array we've been using. -5. Add some test data. - - -### Configure our app to work with mongo -1. Edit our config file (at `src/config/index.js`) so that the returned configuration object includes mongo configuration: - ```javascript - module.exports = { - appName: 'Our Glorious Node Project', - port: 3030, - db: { - host: 'localhost', - dbName: 'fsjs', - } - }; - ``` - -2. Connect to mongo through the mongoose library. In `src/server.js`, somewhere near the top of the file, import mongoose with - ```javascript - // Load mongoose package - const mongoose = require('mongoose'); - ``` - Then, somewhere AFTER the line where you load your configuration, connect with the following - ```javascript - // Connect to MongoDB and create/use database as configured - mongoose.connection.openUri(`mongodb://${config.db.host}/${config.db.dbName}`); - ``` - - -### Build the model - -1. In the `src/models` directory, create an empty file called `file.model.js` -2. At the top of that file, pull in mongoose - ```javascript - // Load mongoose package - const mongoose = require('mongoose'); - ``` - -3. Create a schema - ```javascript - const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, - }); - ``` - Notice that the `title` and `description` fields are also present in our faked data (`/src/routes/index.js`). We've also added a new field called `created_at`, which will be a Date and will default to the current time. - -4. Turn that schema in to a mongoose model, register it, and export it - ```javascript - const File = mongoose.model('File', FileSchema); - module.exports = File; - ``` - A lot is going on here. We are storing the `File` schema inside the mongoose object (which will make it available anywhere in your application). We're also giving a name ("File") so we can distinguish it from any other model we may want to register. We're also exporting the model from this module. - -5. Make sure that the `file.model.js` script is run by `require`-ing it somewhere...like in `src/server.js`, below the line where we connect mongoose to mongo: - ```javascript - // Import all models - require('./models/file.model.js'); - ``` - -## Connect to our app -1. In `src/routes/index.js`, pull in mongoose at the top of the file. - ```javascript - const mongoose = require('mongoose'); - ``` - -2. Edit the `GET /file` route. Replace our development code with - ```javascript - mongoose.model('File').find({}, function(err, files) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(files); - }); - ``` - **Model.find:** http://mongoosejs.com/docs/api.html#model_Model.find - -3. Restart server and test - **Where did our data go?** - -### What about some test data? -Strategy: On startup, check if there are any files in the database, if not, then add files from a seed file. - -1. Create a file in `/src/models` called `file.seed.json` - ```json - [ - {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, - {"title":"Rules of Cribbage.doc", "description": "9th edition" }, - {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } - ] - ``` - -2. In `file.model.js`, after you create and export the model, get the current count of documents in the collection - ```javascript - File.count({}, function(err, count) { - if (err) { - throw err; - } - // ... - }); - ``` - **Model.count:** http://mongoosejs.com/docs/api.html#model_Model.count - -3. Add the seed data - ```javascript - if (count > 0) return ; - - const files = require('./file.seed.json'); - File.create(files, function(err, newFiles) { - if (err) { - throw err; - } - console.log("DB seeded") - }); - ``` - **Model.create:** http://mongoosejs.com/docs/api.html#model_Model.create diff --git a/week5/src/config/index.js b/week5/src/config/index.js deleted file mode 100644 index 8b6e7d5..0000000 --- a/week5/src/config/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030, - db: { - host: 'localhost', - dbName: 'fsjs', - } -}; diff --git a/week5/src/models/file.model.js b/week5/src/models/file.model.js deleted file mode 100644 index 5166098..0000000 --- a/week5/src/models/file.model.js +++ /dev/null @@ -1,29 +0,0 @@ -// Load mongoose package -const mongoose = require('mongoose'); - -const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, -}); - - -const File = mongoose.model('File', FileSchema); -module.exports = File; - - -File.count({}, function(err, count) { - if (err) { - throw err; - } - - if (count > 0) return ; - - const files = require('./file.seed.json'); - File.create(files, function(err, newFiles) { - if (err) { - throw err; - } - console.log("DB seeded") - }); -}); diff --git a/week5/src/models/file.seed.json b/week5/src/models/file.seed.json deleted file mode 100644 index 6b401c1..0000000 --- a/week5/src/models/file.seed.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, - {"title":"Rules of Cribbage.doc", "description": "9th edition" }, - {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } -] diff --git a/week5/src/models/index.js b/week5/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week5/src/routes/index.js b/week5/src/routes/index.js deleted file mode 100644 index 9e44a08..0000000 --- a/week5/src/routes/index.js +++ /dev/null @@ -1,66 +0,0 @@ -// src/routes/index.js -const router = require('express').Router(); -const mongoose = require('mongoose'); - -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; - - -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -router.get('/file', function(req, res, next) { - mongoose.model('File').find({}, function(err, files) { - if (err) { - console.log(err); - res.status(500).json(err); - } - - res.json(files); - }); -}); - - -router.post('/file', function(req, res, next) { - const newId = '' + FILES.length; - const data = req.body; - data.id = newId; - - FILES.push(data); - res.status(201).json(data); -}); - -router.put('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - file.title = req.body.title; - file.description = req.body.description; - res.json(file); -}); - -router.delete('/file/:fileId', function(req, res, next) { - res.end(`Deleting file '${req.params.fileId}'`); -}); - -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); - -module.exports = router; diff --git a/week5/src/server.js b/week5/src/server.js deleted file mode 100644 index fa63e81..0000000 --- a/week5/src/server.js +++ /dev/null @@ -1,27 +0,0 @@ -// src/server.js -const path = require('path'); -const bodyParser = require('body-parser'); - -// Load mongoose package -const mongoose = require('mongoose'); - -const express = require('express'); -const config = require('./config'); -const router = require('./routes'); - -// Connect to MongoDB and create/use database as configured -mongoose.connect(`mongodb://${config.db.host}/${config.db.dbName}`); - -// Import all models -require('./models/file.model.js'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); -app.use(bodyParser.json()); -app.use('/api', router); - - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week5/src/tester/index.html b/week5/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week5/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week6/index.js b/week6/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week6/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week6/mongoose_diag.png b/week6/mongoose_diag.png deleted file mode 100644 index c40ad4c..0000000 Binary files a/week6/mongoose_diag.png and /dev/null differ diff --git a/week6/package.json b/week6/package.json deleted file mode 100644 index 3117c53..0000000 --- a/week6/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "body-parser": "^1.17.2", - "express": "^4.14.0", - "mongoose": "^4.10.4" - } -} diff --git a/week6/public/index.html b/week6/public/index.html deleted file mode 100644 index 76ff462..0000000 --- a/week6/public/index.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - Our Glorious Node Project - - - - -
-

A wild webpage appears...

-
- - -
- - - - - - - - - diff --git a/week6/public/js/app.js b/week6/public/js/app.js deleted file mode 100644 index 013bd63..0000000 --- a/week6/public/js/app.js +++ /dev/null @@ -1,67 +0,0 @@ - - -function getFiles() { - return $.ajax('/api/file') - .then(res => { - console.log("Results from getFiles()", res); - return res; - }) - .fail(err => { - console.log("Error in getFiles()", err); - throw err; - }); -} - - -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} - - -function toggleAddFileForm() { - console.log("Baby steps..."); - toggleAddFileFormVisibility(); -} - -function toggleAddFileFormVisibility() { - $('#form-container').toggleClass('hidden'); -} - -function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - - const fileData = { - title: $('#file-title').val(), - description: $('#file-description').val(), - }; - - $.ajax({ - type: "POST", - url: '/api/file', - data: JSON.stringify(fileData), - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("We have posted the data"); - refreshFileList(); - toggleAddFileForm(); - }) - .fail(function(error) { - console.log("Failures at posting, we are", error); - }) - - console.log("Your file data", fileData); -} - -function cancelFileForm() { - toggleAddFileFormVisibility(); -} diff --git a/week6/readme.md b/week6/readme.md deleted file mode 100644 index adc8985..0000000 --- a/week6/readme.md +++ /dev/null @@ -1,207 +0,0 @@ -# FSJS Week 6 - Something from Nothing - -**Outline** - -1. Set up for week6 -2. Create a hidable form to add files -4. Client-side function to POST a new files -5. Server-side handler that creates file - - -## 1. Setup Project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - - **OR** if you need to ditch your current changes and pull a fresh copy down, try this: - ``` - git stash - git pull - ``` - -2. Get rid of `week6` (we're going to rebuild it) -``` -rm -rf week6 -``` - -3. Copy `week5` to `week6` -``` -cp -R week5 week6 -cd week6 -``` - -4. Install dependencies -``` -npm install -``` - -**Strategy:** -* A User will visit the site and see a button that reads `Add File`. -* Clicking on this button will cause a blank form (previously not visible) to appear. -* Our user will use that form to add a new File to the database. -* The form has fields for `title` and `description` fields, a `Submit` and a `Cancel` button. -* The `Submit` and `Cancel` buttons do exactly what you think they would do. - * The `Submit` button will trigger a javascript function that grabs the data from the form and POSTs it to an API endpoint (we already have one...remember it?) - * After POSTing the data and receiving a response, the page will refresh the list of Files. - * The `Cancel` button will close the form without POSTing the data -* Clicking the `Add File` button while the form is open has the same effect as clicking `Cancel.` - -## 2. Create a form - - -1. Clean up the look of our webpage by taking advantage of bootstrap's `.container`. Open `public/index.html` and make the first two lines of the `` look like this: - ```html -
-

A wild webpage appears...

-
-
- ``` - -2. Add a button that calls a function when clicked below the file list. - ```html - - ``` - -3. We need that button to do something when we click it. Add an `onclick` handler: - ```html - - ``` - -3. What's that `toggleAddFileForm()` function? We have to create it. Add the following code to the file we created to house our code: `public/js/app.js`. - ```javascript - function toggleAddFileForm() { - console.log("Baby steps..."); - } - ``` - Refresh the page, open a console, and click the button a few times. - -4. Add a section of HTML that will appear and disappear on command. Add this below the `Add File` button. - ```html - - ``` - If you refresh the page, nothing will appear because of bootstrap's `.hidden` class. - -5. Create a javascript function to toggle the visibility of the form container: - ```javascript - function toggleAddFileFormVisibility() { - $('#form-container').toggleClass('hidden'); - } - ``` - - And call that function within `toggleAddFileForm()` - ```javascript - function toggleAddFileForm() { - console.log("Baby steps..."); - toggleAddFileFormVisibility(); - } - ``` - -6. Now insert a form into the `#form-container` - ```html -
-
- - -
-
- - -
- - -
- ``` - Reload the browser and look at our beautiful form. - -7. What about those `onclick` functions? We already know what 'cancel' should do (close the form), but will figure out what `submit` does later. - ```javascript - function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - } - - function cancelFileForm() { - toggleAddFileFormVisibility(); - } - ``` - - At this point, we should have 4 more simple functions in `public/js/app.js` that barely do anything. Let's change that by collecting the form data when we click `submit`: - -8. Add the following to our `submitFileForm` function after the `console.log` line: - ```javascript - function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - - const title = $('#file-title').val(); - const description = $('#file-description').val(); - const fileData = { - title: title, - description: description, - }; - - console.log("Your file data", fileData); - } - ``` - -## jQuery, our POSTing hero - -We're going to POST json-formatted data to an endpoint on our server which will do all the hard work. We already have a `POST /api/file` route, but currently it appends the file data to a static array (remember? We never changed that). - -First, we'll use jquery to POST the data, then we'll fix our POST route. - -1. Add the following to our `submitFileForm` function AFTER we create the fileData object. - ```javascript - $.ajax({ - type: "POST", - url: '/api/file', - data: JSON.stringify(fileData), - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("We have posted the data"); - refreshFileList(); - toggleAddFileFormVisibility(); - }) - .fail(function(error) { - console.log("Failures at posting, we are", error); - }); - ``` - [Documentation for jquery AJAX](https://api.jquery.com/jquery.ajax/) - If we refresh the page and test this, it will work, but we won't be updating the displayed list. Remember that we have that static array thing which we've never changed...let's do that now. - - -## Now, fix the POST route handler - -1. Open the file `src/routes/index.js` and delete everything in our `POST /file` handler. It should look like this when we're done: - ```javascript - router.post('/file', function(req, res, next) { - - }); - ``` - -2. Instead of appending to an array, we will use our mongoose model to insert a new "File" in to the database. Change the `POST /file` handler to the following: - ```javascript - router.post('/file', function(req, res, next) { - const File = mongoose.model('File'); - const fileData = { - title: req.body.title, - description: req.body.description, - }; - - File.create(fileData, function(err, newFile) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(newFile); - }); - }); - ``` - [Documentation for mongoose Model.create](http://mongoosejs.com/docs/api.html#model_Model.create) - - Restart the server, go back to our website and add a new File. Our list of files should update. We can reload the page and/or restart the server and we will still have our newly added file in the list. diff --git a/week6/src/config/index.js b/week6/src/config/index.js deleted file mode 100644 index 8b6e7d5..0000000 --- a/week6/src/config/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030, - db: { - host: 'localhost', - dbName: 'fsjs', - } -}; diff --git a/week6/src/models/file.model.js b/week6/src/models/file.model.js deleted file mode 100644 index 5166098..0000000 --- a/week6/src/models/file.model.js +++ /dev/null @@ -1,29 +0,0 @@ -// Load mongoose package -const mongoose = require('mongoose'); - -const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, -}); - - -const File = mongoose.model('File', FileSchema); -module.exports = File; - - -File.count({}, function(err, count) { - if (err) { - throw err; - } - - if (count > 0) return ; - - const files = require('./file.seed.json'); - File.create(files, function(err, newFiles) { - if (err) { - throw err; - } - console.log("DB seeded") - }); -}); diff --git a/week6/src/models/file.seed.json b/week6/src/models/file.seed.json deleted file mode 100644 index 6b401c1..0000000 --- a/week6/src/models/file.seed.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, - {"title":"Rules of Cribbage.doc", "description": "9th edition" }, - {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } -] diff --git a/week6/src/models/index.js b/week6/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week6/src/routes/index.js b/week6/src/routes/index.js deleted file mode 100644 index a433df6..0000000 --- a/week6/src/routes/index.js +++ /dev/null @@ -1,74 +0,0 @@ -// src/routes/index.js -const router = require('express').Router(); -const mongoose = require('mongoose'); - -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; - - -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -router.get('/file', function(req, res, next) { - mongoose.model('File').find({}, function(err, files) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(files); - }); -}); - - -router.post('/file', function(req, res, next) { - const File = mongoose.model('File'); - const fileData = { - title: req.body.title, - description: req.body.description, - }; - - File.create(fileData, function(err, newFile) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(newFile); - }); -}); - -router.put('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - file.title = req.body.title; - file.description = req.body.description; - res.json(file); -}); - -router.delete('/file/:fileId', function(req, res, next) { - res.end(`Deleting file '${req.params.fileId}'`); -}); - -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); - -module.exports = router; diff --git a/week6/src/server.js b/week6/src/server.js deleted file mode 100644 index fa63e81..0000000 --- a/week6/src/server.js +++ /dev/null @@ -1,27 +0,0 @@ -// src/server.js -const path = require('path'); -const bodyParser = require('body-parser'); - -// Load mongoose package -const mongoose = require('mongoose'); - -const express = require('express'); -const config = require('./config'); -const router = require('./routes'); - -// Connect to MongoDB and create/use database as configured -mongoose.connect(`mongodb://${config.db.host}/${config.db.dbName}`); - -// Import all models -require('./models/file.model.js'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); -app.use(bodyParser.json()); -app.use('/api', router); - - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week6/src/tester/index.html b/week6/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week6/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week7/index.js b/week7/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week7/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week7/mongoose_diag.png b/week7/mongoose_diag.png deleted file mode 100644 index c40ad4c..0000000 Binary files a/week7/mongoose_diag.png and /dev/null differ diff --git a/week7/package.json b/week7/package.json deleted file mode 100644 index 3117c53..0000000 --- a/week7/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "body-parser": "^1.17.2", - "express": "^4.14.0", - "mongoose": "^4.10.4" - } -} diff --git a/week7/public/index.html b/week7/public/index.html deleted file mode 100644 index f7c46f3..0000000 --- a/week7/public/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - Our Glorious Node Project - - - - -
-

A wild webpage appears...

-
- - -
- - - - - - - - - diff --git a/week7/public/js/app.js b/week7/public/js/app.js deleted file mode 100644 index 9f449be..0000000 --- a/week7/public/js/app.js +++ /dev/null @@ -1,104 +0,0 @@ - - -function getFiles() { - return $.ajax('/api/file') - .then(res => { - console.log("Results from getFiles()", res); - return res; - }) - .fail(err => { - console.log("Error in getFiles()", err); - throw err; - }); -} - - -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - - window.fileList = files; - - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} - - -function toggleAddFileForm() { - console.log("Baby steps..."); - setFormData({}); - toggleAddFileFormVisibility(); -} - -function toggleAddFileFormVisibility() { - $('#form-container').toggleClass('hidden'); -} - -function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - - const fileData = { - title: $('#file-title').val(), - description: $('#file-description').val(), - _id: $('#file-id').val(), - }; - - let method, url; - if (fileData._id) { - method = 'PUT'; - url = '/api/file/' + fileData._id; - } else { - method = 'POST'; - url = '/api/file'; - } - - $.ajax({ - type: method, - url: url, - data: JSON.stringify(fileData), - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("We have posted the data"); - refreshFileList(); - toggleAddFileForm(); - }) - .fail(function(error) { - console.log("Failures at posting, we are", error); - }) - - console.log("Your file data", fileData); -} - -function cancelFileForm() { - toggleAddFileFormVisibility(); -} - - -function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - setFormData(file); - toggleAddFileFormVisibility(); - } -} - -function setFormData(data) { - data = data || {}; - - const file = { - title: data.title || '', - description: data.description || '', - _id: data._id || '', - }; - - $('#file-title').val(file.title); - $('#file-description').val(file.description); - $('#file-id').val(file._id); -} diff --git a/week7/readme.md b/week7/readme.md deleted file mode 100644 index d4b65e5..0000000 --- a/week7/readme.md +++ /dev/null @@ -1,274 +0,0 @@ -# FSJS Week 7 - Change is the Only Constant - -**Outline** - -1. Set up for week7 -2. Every file item has an edit button -3. Function to push changes to the server -3. PUT endpoint - - -## 1. Setup Project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - - **OR** if you need to ditch your current changes and pull a fresh copy down, try this: - ``` - git stash - git pull - ``` - -2. Get rid of `week7` (we're going to rebuild it) -``` -rm -rf week7 -``` - -3. Copy `week6` to `week7` -``` -cp -R week6 week7 -cd week7 -``` - -4. Install dependencies -``` -npm install -``` - -**Strategy:** -* A User will visit the site and see an edit button beside each file. -* Clicking on this button will cause a form (previously not visible) to appear. -* This will be the same form that adds a new File. -* That form will have all the current information for the selected file -* Our user will use that form to edit the existing File. -* The `Submit` button will trigger a javascript function that grabs the data from the form and PUTs it to an API endpoint -* After PUTting the data and receiving a response, the page will refresh the list of Files. - -## 2. Add an edit button to each item. - -1. Open `public/index.html` and find the `#list-template` handlebars template we use to render the list of files. Add a button to each item. -```html -
  • - {{title}} - {{description}} - - - -
  • -``` - -2. Add some functionality to that button. Add an `onclick` event handler and its corresponding function. -```html - -``` -And the function goes in `/public/js/app.js` -```javascript -function editFileClick() { - console.log("I will edit for you!"); -} -``` - -This works, but every 'Edit' does the exact same thing when clicked. We want a click to (eventually) open a form with the data for a specific file. We need somehow get the File data in to our `editFileClick()` function. There are dozens of ways of accomplishing this. Here's a straight-forward method: - -Pass the unique File `_id` field to our function in the `onclick` event handler. Then use that id to find the File in an array. We'll need to make sure we have an array of File objects available. - -3. Pass the `_id` parameter to the funciton - ```html - - ``` - And now `console.log()` the result to show it works - ```javascript - function editFileClick(id) { - console.log("I will edit for you", id); - } - ``` - - Take a look at the edit button element to see what's going on here. - -4. Whenever we refresh the list of Files (remember our AJAX call), save that array to a property on the global `window` object. This is done in `refreshFileList()` -```javascript -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - - window.fileList = files; - - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} -``` - -5. In our `onclick` handler, retrieve the file using `Array.find()` -```javascript -function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - console.log("I will edit you!", file); - } else { - console.log("Aw shucks, I didn't find", id) - } -} -``` -[Documentation for Array.find()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find?v=control) - - Refresh the page and click on a few `Edit` buttons to see that it works. - - -6. Edit the `editFileClick()` function so that it opens the form we created last week. When clicked, we should also populate the form with the data we wish to edit. - ```javascript - function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - $('#file-title').val(file.title); - $('#file-description').val(file.description); - toggleAddFileFormVisibility(); - } - } - ``` - -7. Hey, what about the `_id` field? That seems important. Add a hidden input to the form and set that when we click edit. - ```html -
    - - ... - ``` - - ```javascript - function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - $('#file-title').val(file.title); - $('#file-description').val(file.description); - $('#file-id').val(file._id); - toggleAddFileFormVisibility(); - } - } - ``` - -8. Problem, what if we click `Edit`, close the form and then try to add a new File? When we click `Add File` we expect to see a blank form, but instead we see data from the previously edited File. Since we are reusing this form, we need a way to clear the data. Let's pull all the logic for setting a form's data out in to it's own function. - ```javascript - function setFormData(data) { - data = data || {}; - - const file = { - title: data.title || '', - description: data.description || '', - _id: data._id || '', - }; - - $('#file-title').val(file.title); - $('#file-description').val(file.description); - $('#file-id').val(file._id); - } - ``` - Now, we use that function in `editFileClick()` and `toggleAddFileForm()` - - ```javascript - function toggleAddFileForm() { - console.log("Baby steps..."); - setFormData({}); - toggleAddFileFormVisibility(); - } - ``` - ```javascript - function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - setFormData(file); - toggleAddFileFormVisibility(); - } - } - ``` - -## Push our changes to the server. - - Most of the hard work on the front-end has been done. Really, the only difference between creating a new file and editing an existing one is that when creating, we `POST` to the server and we don't have an `_id` field, while when editing, we `PUT` to the server AND the URL is slightly different (we add the `_id` field to the url). - - We can accomplish this by checking to see if `#file-id` has a value. If it does, we are editing, if it doesn't we are creating. - -1. In `submitFileForm()` get the `#file-id` value and check if we are PUTting or POSTing - ```javascript - function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - - const fileData = { - title: $('#file-title').val(), - description: $('#file-description').val(), - _id: $('#file-id').val(), - }; - - let method, url; - if (fileData._id) { - method = 'PUT'; - url = '/api/file/' + fileData._id; - } else { - method = 'POST'; - url = '/api/file'; - } - - $.ajax({ - type: method, - url: url, - data: JSON.stringify(fileData), - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("We have posted the data"); - refreshFileList(); - toggleAddFileForm(); - }) - .fail(function(error) { - console.log("Failures at posting, we are", error); - }) - - console.log("Your file data", fileData); - } - ``` - That should do it, but when we try to submit an error, we get a 404 response. We have to create the PUT endpoint. - - -## Handle that PUT - -1. In `/src/routes/index.js`, clear out our previous, Array-based `PUT /api/file/:fileId` route: - ```javascript - router.put('/file/:fileId', function(req, res, next) { - - }); - ``` - -2. Our strategy here is to find the file we're trying to edit in the database, then edit it, then save it - ```javascript - router.put('/file/:fileId', function(req, res, next) { - const File = mongoose.model('File'); - const fileId = req.params.fileId; - - File.findById(fileId, function(err, file) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - if (!file) { - return res.status(404).json({message: "File not found"}); - } - - file.title = req.body.title; - file.description = req.body.description; - - file.save(function(err, savedFile) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - res.json(savedFile); - }) - - }) -}); -``` diff --git a/week7/src/config/index.js b/week7/src/config/index.js deleted file mode 100644 index 8b6e7d5..0000000 --- a/week7/src/config/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030, - db: { - host: 'localhost', - dbName: 'fsjs', - } -}; diff --git a/week7/src/models/file.model.js b/week7/src/models/file.model.js deleted file mode 100644 index 5166098..0000000 --- a/week7/src/models/file.model.js +++ /dev/null @@ -1,29 +0,0 @@ -// Load mongoose package -const mongoose = require('mongoose'); - -const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, -}); - - -const File = mongoose.model('File', FileSchema); -module.exports = File; - - -File.count({}, function(err, count) { - if (err) { - throw err; - } - - if (count > 0) return ; - - const files = require('./file.seed.json'); - File.create(files, function(err, newFiles) { - if (err) { - throw err; - } - console.log("DB seeded") - }); -}); diff --git a/week7/src/models/file.seed.json b/week7/src/models/file.seed.json deleted file mode 100644 index 6b401c1..0000000 --- a/week7/src/models/file.seed.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, - {"title":"Rules of Cribbage.doc", "description": "9th edition" }, - {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } -] diff --git a/week7/src/models/index.js b/week7/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week7/src/routes/index.js b/week7/src/routes/index.js deleted file mode 100644 index a99d9c6..0000000 --- a/week7/src/routes/index.js +++ /dev/null @@ -1,89 +0,0 @@ -// src/routes/index.js -const router = require('express').Router(); -const mongoose = require('mongoose'); - -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; - - -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -router.get('/file', function(req, res, next) { - mongoose.model('File').find({}, function(err, files) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(files); - }); -}); - - -router.post('/file', function(req, res, next) { - const File = mongoose.model('File'); - const fileData = { - title: req.body.title, - description: req.body.description, - }; - - File.create(fileData, function(err, newFile) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(newFile); - }); -}); - -router.put('/file/:fileId', function(req, res, next) { - const File = mongoose.model('File'); - const fileId = req.params.fileId; - - File.findById(fileId, function(err, file) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - if (!file) { - return res.status(404).json({message: "File not found"}); - } - - file.title = req.body.title; - file.description = req.body.description; - - file.save(function(err, savedFile) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - res.json(savedFile); - }) - - }) -}); - -router.delete('/file/:fileId', function(req, res, next) { - res.end(`Deleting file '${req.params.fileId}'`); -}); - -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); - -module.exports = router; diff --git a/week7/src/server.js b/week7/src/server.js deleted file mode 100644 index fa63e81..0000000 --- a/week7/src/server.js +++ /dev/null @@ -1,27 +0,0 @@ -// src/server.js -const path = require('path'); -const bodyParser = require('body-parser'); - -// Load mongoose package -const mongoose = require('mongoose'); - -const express = require('express'); -const config = require('./config'); -const router = require('./routes'); - -// Connect to MongoDB and create/use database as configured -mongoose.connect(`mongodb://${config.db.host}/${config.db.dbName}`); - -// Import all models -require('./models/file.model.js'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); -app.use(bodyParser.json()); -app.use('/api', router); - - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week7/src/tester/index.html b/week7/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week7/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/week8/index.js b/week8/index.js deleted file mode 100644 index 440ef30..0000000 --- a/week8/index.js +++ /dev/null @@ -1 +0,0 @@ -require('./src/server'); diff --git a/week8/mongoose_diag.png b/week8/mongoose_diag.png deleted file mode 100644 index c40ad4c..0000000 Binary files a/week8/mongoose_diag.png and /dev/null differ diff --git a/week8/package.json b/week8/package.json deleted file mode 100644 index 3117c53..0000000 --- a/week8/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "cl_project", - "version": "1.0.0", - "description": "This is a sample node project", - "main": "index.js", - "scripts": { - "start": "nodemon index.js" - }, - "keywords": [ - "code", - "louisville", - "sample", - "project" - ], - "author": "Aaron W. Johnson", - "license": "ISC", - "dependencies": { - "body-parser": "^1.17.2", - "express": "^4.14.0", - "mongoose": "^4.10.4" - } -} diff --git a/week8/public/index.html b/week8/public/index.html deleted file mode 100644 index f2f8964..0000000 --- a/week8/public/index.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - Our Glorious Node Project - - - - -
    -

    A wild webpage appears...

    -
    - - -
    - - - - - - - - - diff --git a/week8/public/js/app.js b/week8/public/js/app.js deleted file mode 100644 index 911d7e1..0000000 --- a/week8/public/js/app.js +++ /dev/null @@ -1,122 +0,0 @@ - - -function getFiles() { - return $.ajax('/api/file') - .then(res => { - console.log("Results from getFiles()", res); - return res; - }) - .fail(err => { - console.log("Error in getFiles()", err); - throw err; - }); -} - - -function refreshFileList() { - const template = $('#list-template').html(); - const compiledTemplate = Handlebars.compile(template); - - getFiles() - .then(files => { - - window.fileList = files; - - const data = {files: files}; - const html = compiledTemplate(data); - $('#list-container').html(html); - }) -} - - -function toggleAddFileForm() { - console.log("Baby steps..."); - setFormData({}); - toggleAddFileFormVisibility(); -} - -function toggleAddFileFormVisibility() { - $('#form-container').toggleClass('hidden'); -} - -function submitFileForm() { - console.log("You clicked 'submit'. Congratulations."); - - const fileData = { - title: $('#file-title').val(), - description: $('#file-description').val(), - _id: $('#file-id').val(), - }; - - let method, url; - if (fileData._id) { - method = 'PUT'; - url = '/api/file/' + fileData._id; - } else { - method = 'POST'; - url = '/api/file'; - } - - $.ajax({ - type: method, - url: url, - data: JSON.stringify(fileData), - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("We have posted the data"); - refreshFileList(); - toggleAddFileForm(); - }) - .fail(function(error) { - console.log("Failures at posting, we are", error); - }) - - console.log("Your file data", fileData); -} - -function cancelFileForm() { - toggleAddFileFormVisibility(); -} - - -function editFileClick(id) { - const file = window.fileList.find(file => file._id === id); - if (file) { - setFormData(file); - toggleAddFileFormVisibility(); - } -} - -function deleteFileClick(id) { - if (confirm("Are you sure?")) { - $.ajax({ - type: 'DELETE', - url: '/api/file/' + id, - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("File", id, "is DOOMED!!!!!!"); - refreshFileList(); - }) - .fail(function(error) { - console.log("I'm not dead yet!", error); - }) - } -} - -function setFormData(data) { - data = data || {}; - - const file = { - title: data.title || '', - description: data.description || '', - _id: data._id || '', - }; - - $('#file-title').val(file.title); - $('#file-description').val(file.description); - $('#file-id').val(file._id); -} diff --git a/week8/readme.md b/week8/readme.md deleted file mode 100644 index 2b45a69..0000000 --- a/week8/readme.md +++ /dev/null @@ -1,147 +0,0 @@ -# FSJS Week 8 - Delete the negative; Accentuate the positive! - -**Outline** - -1. Set up for week8 -2. What is a soft delete? -3. Update our model and handlers -4. Delete handler -5. Baby-step our way to a delete button - - -## 1. Setup Project -1. (optional) Clone the project -``` -git clone https://github.com/CodeLouisville/FSJS-class-project.git -cd FSJS-class-project -``` - - **OR** if you need to ditch your current changes and pull a fresh copy down, try this: - ``` - git stash - git pull - ``` - -2. Get rid of `week8` (we're going to rebuild it) -``` -rm -rf week8 -``` - -3. Copy `week7` to `week8` -``` -cp -R week7 week8 -cd week8 -``` - -4. Install dependencies -``` -npm install -``` - -## 2. What is a soft delete - -**Deleting Can Be Hazardous to your Health** -It is difficult to make deleting (as in, actually removing something from the database) save. Meaning, if you give users the ability to destroy data, eventually they will do it by accident. Without some means of recovering that data, deleting can make managers and clients sad. - -**So Don't Do It** -Simply mark a database entry as `deleted` instead. That way, you can exclude "deleted" items from your searches AND recover those items (undelete with ease). - -## 3. So let's apply that idea to our model -1. In `/src/models/file.model.js`, update our model so that it has a `deleted` field: -```javascript -const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, - deleted: {type: Boolean, default: false} -}); -``` - -2. Now make sure that our route handlers know to exclude "deleted" items. In `src/routes/index.js` update the `GET /file` handler: -```javascript -router.get('/file', function(req, res, next) { - mongoose.model('File').find({deleted: {$ne: true}}, function(err, files) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(files); - }); -}); -``` -So, why not just `{deleted: false}`? -[Documentation for Mongo's $ne operator](https://docs.mongodb.com/manual/reference/operator/query/ne/) - -## 4. Let's do some deleting -1. We can now update the `DELETE /file/:fileId` handler in `src/routes/index.js` to actually do something. Since we aren't removing the file, "deleting" will basically be updating the file. In other works `DELETE /file/:fileId` will look really similar to `PUT /file/:fileId`: -```javascript -router.delete('/file/:fileId', function(req, res, next) { - const File = mongoose.model('File'); - const fileId = req.params.fileId; - - File.findById(fileId, function(err, file) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - if (!file) { - return res.status(404).json({message: "File not found"}); - } - - file.deleted = true; - - file.save(function(err, doomedFile) { - res.json(doomedFile); - }) - - }) -}); -``` -How would you implement an `undelete` operation? - -## 5. Baby-step our way through the front-end stuff -1. Make a "Delete" button appear by each file, just next to the "Edit" button. Open `public/index.html` and add this just after the edit button -```html - -``` - -2. Now make it do something by adding an `onclick` handler (we can copy/paste from the "Edit" button and then change it to suit our needs): -```html - -``` - -3. Create the `deleteFileClick()` function in `public/js/app.js`: -```javascript -function deleteFileClick(id) { - console.log("File", id, "is DOOMED!!!!!!"); -} -``` - -4. Er....maybe we should ask for confirmation before doing this: -```javascript -function deleteFileClick(id) { - console.log("File", id, "is DOOMED!!!!!!"); -} -``` - -5. OK, now send the `DELETE` message to `/file/:fileId`. (We can look at `submitFileForm()` to remind ourselves how to do it): -```javascript -function deleteFileClick(id) { - if (confirm("Are you sure?")) { - $.ajax({ - type: 'DELETE', - url: '/api/file/' + id, - dataType: 'json', - contentType : 'application/json', - }) - .done(function(response) { - console.log("File", id, "is DOOMED!!!!!!"); - refreshFileList(); - }) - .fail(function(error) { - console.log("I'm not dead yet!", error); - }) - } -} -``` diff --git a/week8/src/config/index.js b/week8/src/config/index.js deleted file mode 100644 index 8b6e7d5..0000000 --- a/week8/src/config/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// src/config/index.js - -module.exports = { - appName: 'Our Glorious Node Project', - port: 3030, - db: { - host: 'localhost', - dbName: 'fsjs', - } -}; diff --git a/week8/src/models/file.model.js b/week8/src/models/file.model.js deleted file mode 100644 index 6fea2dc..0000000 --- a/week8/src/models/file.model.js +++ /dev/null @@ -1,30 +0,0 @@ -// Load mongoose package -const mongoose = require('mongoose'); - -const FileSchema = new mongoose.Schema({ - title: String, - description: String, - created_at: { type: Date, default: Date.now }, - deleted: {type: Boolean, default: false} -}); - - -const File = mongoose.model('File', FileSchema); -module.exports = File; - - -File.count({}, function(err, count) { - if (err) { - throw err; - } - - if (count > 0) return ; - - const files = require('./file.seed.json'); - File.create(files, function(err, newFiles) { - if (err) { - throw err; - } - console.log("DB seeded") - }); -}); diff --git a/week8/src/models/file.seed.json b/week8/src/models/file.seed.json deleted file mode 100644 index 6b401c1..0000000 --- a/week8/src/models/file.seed.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - {"title":"Satellite of Love Plans.svg", "description": "Includes fix for exhaust port vulnerability" }, - {"title":"Rules of Cribbage.doc", "description": "9th edition" }, - {"title":"avengers_fanfic.txt", "description": "PRIVATE DO NOT READ" } -] diff --git a/week8/src/models/index.js b/week8/src/models/index.js deleted file mode 100644 index e69de29..0000000 diff --git a/week8/src/routes/index.js b/week8/src/routes/index.js deleted file mode 100644 index eb06892..0000000 --- a/week8/src/routes/index.js +++ /dev/null @@ -1,107 +0,0 @@ -// src/routes/index.js -const router = require('express').Router(); -const mongoose = require('mongoose'); - -const FILES = [ - {id: 'a', title: 'cutecat1.jpg', description: 'A cute cat'}, - {id: 'b', title: 'uglycat1.jpg', description: 'Just kidding, all cats are cute'}, - {id: 'c', title: 'total_recall_poster.jpg', description: 'Quaid, start the reactor...'}, - {id: 'd', title: 'louisville_coffee.txt', description: 'Coffee shop ratings'}, -]; - - -router.use('/doc', function(req, res, next) { - res.end(`Documentation http://expressjs.com/`); -}); - -router.get('/file', function(req, res, next) { - mongoose.model('File').find({deleted: {$ne: true}}, function(err, files) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(files); - }); -}); - - -router.post('/file', function(req, res, next) { - const File = mongoose.model('File'); - const fileData = { - title: req.body.title, - description: req.body.description, - }; - - File.create(fileData, function(err, newFile) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - - res.json(newFile); - }); -}); - -router.put('/file/:fileId', function(req, res, next) { - const File = mongoose.model('File'); - const fileId = req.params.fileId; - - File.findById(fileId, function(err, file) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - if (!file) { - return res.status(404).json({message: "File not found"}); - } - - file.title = req.body.title; - file.description = req.body.description; - - file.save(function(err, savedFile) { - if (err) { - console.error(err); - return res.status(500).json(err); - } - res.json(savedFile); - }) - - }) -}); - -router.delete('/file/:fileId', function(req, res, next) { - const File = mongoose.model('File'); - const fileId = req.params.fileId; - - File.findById(fileId, function(err, file) { - if (err) { - console.log(err); - return res.status(500).json(err); - } - if (!file) { - return res.status(404).json({message: "File not found"}); - } - - file.deleted = true; - - file.save(function(err, doomedFile) { - res.json(doomedFile); - }) - - }) -}); - -router.get('/file/:fileId', function(req, res, next) { - const {fileId} = req.params; - // same as 'const fileId = req.params.fileId' - - const file = FILES.find(entry => entry.id === fileId); - if (!file) { - return res.status(404).end(`Could not find file '${fileId}'`); - } - - res.json(file); -}); - -module.exports = router; diff --git a/week8/src/server.js b/week8/src/server.js deleted file mode 100644 index fa63e81..0000000 --- a/week8/src/server.js +++ /dev/null @@ -1,27 +0,0 @@ -// src/server.js -const path = require('path'); -const bodyParser = require('body-parser'); - -// Load mongoose package -const mongoose = require('mongoose'); - -const express = require('express'); -const config = require('./config'); -const router = require('./routes'); - -// Connect to MongoDB and create/use database as configured -mongoose.connect(`mongodb://${config.db.host}/${config.db.dbName}`); - -// Import all models -require('./models/file.model.js'); - -const app = express(); -const publicPath = path.resolve(__dirname, '../public'); -app.use(express.static(publicPath)); -app.use(bodyParser.json()); -app.use('/api', router); - - -app.listen(config.port, function() { - console.log(`${config.appName} is listening on port ${config.port}`); -}); diff --git a/week8/src/tester/index.html b/week8/src/tester/index.html deleted file mode 100644 index 2b263fa..0000000 --- a/week8/src/tester/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - sdfjhs - - - SKDJHFLKSJDHFLKSDJ - - diff --git a/z-deploy/README.md b/z-deploy/README.md deleted file mode 100644 index e85c4d6..0000000 --- a/z-deploy/README.md +++ /dev/null @@ -1,144 +0,0 @@ -# How to Deploy your Shiny new Node App - -Got something working? Want to show someone? - -Let's put it out in the world. - -## Deploy Mongo at mLab - -Hosted mongodb (free tier = < .5G) -https://mlab.com - -1. Sign up -2. Verify email (required) -3. Create new mongodb deployment -4. Select "Amazon", "Single-node", "Sandbox = Free" -5. Type in a "Database Name" like `fsjs_demo` or your project's name -6. Create button (submit form) - -![ss](https://i.imgur.com/N4NpbON.png) - -Once created, click on your new db. - -Click on `Users` and `Add database user` - -Give it a strong user/pass. _(pro tip, don't include `@` or `:` or `*`)_ - -Eg: `fsjsdb` / `35cqfvmbxpXMw$5mM$$WsJav3JH&` _(not actual value)_ - -Copy the connection string from the top of this page: - -> To connect using a driver via the standard MongoDB URI (what's this?): -> `mongodb://:@ds139242.mlab.com:39242/fsjs_demo` - -Take a note and assemble the connection string in your notes like this (you will use it later): - -`mongodb://fsjsdb:35cqfvmbxpXMw$5mM$$WsJav3JH&@ds139242.mlab.com:39242/fsjs_demo` - -Here's a breakdown: - -> `mongodb://` the protocol -> `fsjsdb` the username who the app can use to access the database -> `:` splits user and pass -> `35cqfvmbxpXMw$5mM$$WsJav3JH&` the user's password -> `@` splits the auth from domain -> `ds139242.mlab.com` the domain name of the database, from mlab -> `:` splits the domain and port -> `39242` the port of the database from mlab -> `/` splits the host from the "path" or in this case the "dbname" -> `fsjs_demo` the name of our database - -## Deploy Node at now - -Super, Crazy, Wildly simple node deployments -https://zeit.co/now#get-started - -1. [install](https://zeit.co/download) their desktop `now` app (convenient, optional, also get their [cli](https://zeit.co/download#command-line)) -2. open the app, walk through the tutorial, install the command line tool, enter your email -3. verify the email, you should get a "hooray" -4. click the `get started` button to show you the UI in the GUI -5. select deploy, browse to your project folder (the one with the `package.json` file in it) - -![ss](https://i.imgur.com/middH4S.png) -![ss](https://i.imgur.com/k8vWtGn.png) -![ss](https://i.imgur.com/NcgnrME.png) - -Now... it deploys... - -### Did you get a build error? - -I did, because `package.json` has `scripts` which has `"start": "nodemon index.js"` - -`nodemon` is a NPM tool we installed onto our machines to make development easier, "fancy start". - -So I changed the `package.json` scripts section to the following, so start is basic, and dev is fancy. - -``` - "scripts": { - "start": "node index.js", - "dev": "nodemon index.js" - }, -``` - -Now you can use nodemon locally with `npm run dev` - -Re-deploy: - -Now you can delete the deployment in now: - -> Now -> Deployments -> -> delete -> confirm - -![ss](https://i.imgur.com/jHJaARx.png) - -Now deploy again. - -### Did you get a build error? - -I did, because the node app can't connect to the mongo database... - -That makes sense, we never told our app where the new database is... - -Edit `src/config/index.js` - -> replace the host, and name database config with the full connection url - -``` -module.exports = { - appName: 'Our Glorious Node Project', - // TODO make this environment aware and switch automatically - // port: 3030, - // mongo_url: 'mongodb://localhost/fsjs', - port: 80, - mongo_url: 'mongodb://fsjsdb:35cqfvmbxpXMw$5mM$$WsJav3JH&@ds139242.mlab.com:39242/fsjs_demo', -}; -``` - -Edit `src/server.js` - -> replace the connection string line to the complete one from the config - -``` -// Connect to MongoDB and create/use database as configured -mongoose.connect(config.mongo_url); -``` - -Re-deploy: - -Now you can delete the deployment in now: - -> Now -> Deployments -> -> delete -> confirm - -![ss](https://i.imgur.com/jHJaARx.png) - -Now deploy again. - - -### Did you get it to work? - -I did. - -![ss](https://puu.sh/wvOwK/fc1132e182.png) - -Bonus points, add `/_src` to the end of the domain name... and you can see your source code - -![ss](https://i.imgur.com/0NWxAAw.png)