work work work

master
Thom Page 10 years ago
parent b928046f2d
commit 6f4b8db799

@ -0,0 +1,48 @@
## EXPRESS CALCULATOR
Tonight you'll make a calculator using node and express. It's not very fancy looking. But it will serve as a proof-of-concept for using express and accessing the `req.params` object.
1. make a directory called `calc`
2. **go into the directory**
3. touch `server.js`
4. `npm init`
5. `npm install --save express`
6. require and set up express at the top of `server.js`
- refer to class notes for syntax
7. add a listener for port 3000
8. Make a GET route for `multiply` that has two variable destinations corresponding to two numbers that will be multiplied. The syntax for the route will look like this:
```
app.get('/multiply/:num1/:num2', function(req, res) {
res.send( // something );
});
```
Write the code that will multiply the numbers that the user sends through in the url, and respond with the answer.
You will need to access `req.params.num1` and `req.params.num2` to get it to work.
1. Make another route for add.
2. Make another route for subtract.
3. Make another route for divide.
### Running the server
In the directory, run `nodemon` to run your server.
See the response of your server in your browser at `localhost:3000`.

@ -0,0 +1,27 @@
# POKEMON JSON
## Express app for Pokemon data
Tonight you'll be making an app for displaying Pokemon JSON data.
### Directions
- Inside package.json, `express` is defined as a dependency. You can simply run `npm install` without any extra arguments in the project directory to install all of the dependencies listed in package.json
- Run `npm install` in the pokemon_express_one directory.
### Starter Code
- All the prompts for this homework are located in `server.js`. Simply follow the prompts and write in the server.js to complete the homework.
- A massive collection of Pokemon data is stored inside `poke_array.js`. This data is an *array* of *objects* that is ready to export using module.exports. You don't need to modify this file.
- You will need to import / reference this data in your `server.js` using the `require` keyword, specifying a path to the file, and saving it to a variable.
- The app is simply going to send JSON to the client.
- The specific JSON that user gets back will depend on the url requested by the user in the client. For some of the prompts, this may require some programming!
- Start simply, build the app piece by piece testing each piece along the way.

@ -0,0 +1,15 @@
{
"name": "express_one",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.13.4"
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,86 @@
// Set up your express dependency here:
// >>
// Require the poke_array.js file here.
// Save it to a variable called data
// >>
// Add a listener for port 3000:
// >>
// ROUTES:
app.get('/', function(req, res) {
res.send('Go to /pokemon to see how many pokemons there are');
});
// Make a GET route '/pokemon' that will res.send a message:
// The message should tell the user the length of the pokemon array.
// >>
// Make a GET route '/pokemon/index/:index' that will res.send a specific
// pokemon's data. Use the value in req.params.index to use as the index of the
// element of the array to display.
//
// Example: a user goes to '/pokemon/index/0' in the browser and all the JSON data
// for Bulbasaur (the pokemon at index 0) will be displayed.
// >>
// Make a GET route '/pokemon/name/:name' that will res.send a specific
// pokemon's data according to the pokemon's name. You will need to loop through the
// array and send the element whose name value is equivalent to the
// name sent through in req.params.name.
//
// Example: a user goes to '/pokemon/name/Charizard' in the browser and all the
// JSON data for Charizard will be displayed.
// >>
// Make a GET route '/pokemon/stats' that will res.send an array of objects
// of all of the stats for all of the pokemon.
//
// Example: a user goes to '/pokemon/stats' in the browser and they will see an
// array, and the array will contain all the stats for
// the first pokemon in an object, and under that, the stats for the
// second pokemon in an object, etc.
//
// Hint: You won't have to make any empty objects but you might want to
// make an empty array for to push objects in.
//
// Bearing in mind, the client can only accept one res.send.
// >>
// BONUS
// In your '/pokemon/name/:name' route, add an *else* statement that will display
// a different message if the name does not match any names in the array.
// If you don't get the results you anticipated, figure out why not.

@ -0,0 +1,72 @@
# POKE EXPRESS TWO -- **NO PROMPTS!!!**
![eh](http://orig10.deviantart.net/54d7/f/2013/265/a/b/w_by_professorlayton22-d6nd2yl.jpg)
This weekend you will be making a Pokemon app that displays data inside server-side rendered views.
The app will adhere to MVC structure with **Models**, **Views**, and **Controllers**
For now, a **Model** is the raw data that you use-- this data can eventually be populated on to your pages.
A **Controller** handles requests from the client and does all the routing. The **Controller** tells which **Views** to use which data from the **Models**.
A **View** renders the data by instruction from the **Controller**.
## App
- When a user goes to the '/pokemon' route they will see an `index` of pokemon: an image of each pokemon rendered to the page.
- When a user clicks on a pokemon image, they will be taken to that pokemon's `show` page, and will see the individual pokemon's name, image, types, and stats (hp, attack, and defense only).
### Requirements
You will need a `models` folder, a `controllers` folder, and a `views folder`.
Your routes should be within a `pokemon.js` file within controllers. You should use `express.Router()`.
### Structure
Your folders for the views, and controllers have been **deleted**. All you get is a models folder. Within `models` is a `pokemon.js` file with the the raw data.
### Project Directions
You don't get any directions. This is what you have chosen.
### Controller
- You've got to have a controller that handles the logic for the '/pokemon' routes. The controller should have two routes, one for displaying an index of all the pokemon, and one for showing a single pokemon according to the user's input. **further directions redacted**
### Views
- You'll need two views:
- `index.ejs`
- `show.ejs`
**show.ejs**
This view will show the data of a single pokemon. Using ejs, this view should display:
- The pokemon's name
- The image of the pokemon
- An unordered list of the Pokemon's types (eg. water, poison, etc). ejs can render an array, however, to get a decent layout for each item in the types array you'll need to use a loop.
- The pokemon's stats for HP, ATTACK, and DEFENSE.
**index.ejs**
This view will show **only the images** of each pokemon. All 151 images. (You'll need to use a loop in the ejs).
When the user clicks on a pokemon's image, they will be taken to that pokemon's show page. **further directions redacted**
## BONUS
Add extra style and functionality to your page with css and javascript using a `public` folder to store your static assets.

@ -0,0 +1,23 @@
// Require express so that we can set the router
// set express.Router() to a variable, router
// require the pokemon model and save it to a variable, Pokemon
// router.get '/', and send all the model data to the 'index.ejs' view
// router.get '/:id', and send the specific pokemon's data to be rendered
// on the 'show.ejs' view. In this case, the :id will be used to refer to
// the index of the pokemon in the pokemon.js array. Remember req.params.
// export the router so the middleware can use it

@ -0,0 +1,65 @@
# POKE EXPRESS TWO
![eh](http://orig10.deviantart.net/54d7/f/2013/265/a/b/w_by_professorlayton22-d6nd2yl.jpg)
This weekend you will be making a Pokemon app that displays data inside server-side rendered views.
The app will adhere to MVC structure with **Models**, **Views**, and **Controllers**
For now, a **Model** is the raw data that you use-- this data can eventually be populated on to your pages.
A **Controller** handles requests from the client and does all the routing. The **Controller** tells which **Views** to use which data from the **Models**.
A **View** renders the data by instruction from the **Controller**.
## App
- When a user goes to the '/pokemon' route they will see an `index` of pokemon: an image of each pokemon rendered to the page.
- When a user clicks on a pokemon image, they will be taken to that pokemon's `show` page, and will see the pokemon's name, image, types, and stats (hp, attack, and defense only).
### Structure
Your folders for the models, views, and controllers have already been made. The raw data is in the `pokemon.js` file in the models folder. The controllers folder has a `pokemonController.js` file with prompts. The views folder is empty, and it's up to you to make the appropriate folders and files within it.
### Directions
- In the root of the project, `npm init`. This will give you a `package.json`
- `npm install --save express`
- in `server.js` set up your server according to the prompts
- refer to Friday's class notes for syntax
- `npm install --save ejs`
- in the `pokemonController.js` file, set up your controller. The controller will have two routes, one for displaying an index of all the pokemon, and one for showing a single pokemon according to the user's input. Fill out `pokemonController.js` according to the prompts.
- refer to Friday's class notes for syntax
- Make the views. Make sure you installed ejs.
### Views
In your views folder, make another folder called `pokemon` for all your pokemon views.
First, make your `show.ejs` view.
This view will show the data of a single pokemon. Using ejs, this view should display:
- The pokemon's name
- The image of the pokemon
- An unordered list of the Pokemon's types (eg. water, poison, etc). ejs can render an array, however, to get a decent layout for each item in the types array you'll need to use a loop.
- The pokemon's stats for HP, ATTACK, and DEFENSE.
Next, make your `index.ejs` view.
This view will show only the images of each pokemon. All 151 images. (You'll need to use a loop in the ejs).
When the user clicks on a pokemon's image, they will be taken to that pokemon's show page. You can use an `<a href="">` tag to accomplish this.
## BONUS
Add extra style and functionality to your page with css and javascript using a `public` folder to store your static assets.
```
app.use(express.static('public'));
```

@ -0,0 +1,12 @@
// SET UP EXPRESS
// Require the pokemon routes controller and set it to a variable
// pokemonController
// app.use the pokemonController as middleware for the
// route '/pokemon'
// app.listen on port 3000

@ -0,0 +1,110 @@
# CRAMPIRES
### Create and Read some Vampires
![](http://newscenter.sdsu.edu/sdsu_newscenter/images/stories/Bela_Lugosi.jpg)
![](http://newscenter.sdsu.edu/sdsu_newscenter/images/stories/Bela_Lugosi.jpg)
![](http://newscenter.sdsu.edu/sdsu_newscenter/images/stories/Bela_Lugosi.jpg)
### The CR in CRUD
CRUD stands for Create, Read, Update, and Destroy-- these are the fundamental actions we perform on data.
Tonight's homework is to make an app that will both **Read** and **Create** data for a single model (Vampires). **Update** and **Destroy** will come later.
### RESTFUL routing
There are seven RESTFUL routes, but tonight we are only using four.
**VIEW** routes (GET):
- `index` displays an index of all resources.
- `show` displays just one resource.
- `new` provides a form for adding a new resources.
- `edit` provides a filled-out form for an existing resource.
The routes that have views are sent from a GET request.
**REDIRECT** routes (POST, PUT, DELETE):
- `create` takes the data from the `new` form.
- `update` takes the data from the `edit` form.
- `destroy` removes data.
The routes that have redirects are sent from POST, PUT, and DELETE requests.
```
In an app with full RESTFUL routes, you will have **four** views and **three** redirects.
Later on, you could of course combine views to reduce navigation, but for now, there are four.
Tonight's homework will use three of these views, `index`, `show`, and `new`, and just one redirect, `create`.
```
### APP
The app will show a list of vampire names. You click on 'em, they go to a show page.
The app will also be able to store new vampires. You click on a 'new vampire' link, a new vampire gets made and will appear on the index.
### DIRECTIONS
- Make a new Express app called `crampires`.
- Set up your MVC architecture.
- Run `npm install` to install all the dependencies that are already in `package.json`.
### Controllers
- *REPS*: Make your `index` and `show` routes for the vampires in the vampires model.
- URI convention for index: GET `/vampires`
- URI convention for show: GET `/vampires/:id`
- Make a `new` route. All this should do is render the `new` view, you don't need to pass it data.
- URI convention for new: GET `/vampires/new`
- Place your `new` route above your `show route`, or the user will never get to it (they will always go to the `show` route instead). Can you explain why this might be?
##### CREATE and req.body
- Make a `create` route.
- URI convention for create: POST `/vampires`
...
- This will add the data from `new` into the Vampires array, and `redirect` to the `index`. The data will come from the request object-- inside an object called `req.body`. Does `req.body` exist without `body-parser`? Well no. `body-parser` adds in an empty body object to the request object that can later be populated with data. You can test the existence of req.body by console.logging req with and without `body-parser`.
- You will need to set up `body-parser` in your `server.js`.
- Once you have required body-parser, this is the code to get it to work:
```
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
```
Note that you can find this code in the body-parser docs on the `npmjs` site.
#### Testing POST requests
1. ##### Network Tab
You can see the POST request go through in the Network tab in the Chrome console. Open up the console, hit the submit button for the request, and you will see the requests load. Click on the POST request, select the Headers, and scroll down to the bottom where you will see the form data.
This is good way to see if the form data has even been passed through the browser.
2. ##### Postman / cURL
You can use Postman or cURL to send data to a server. Send data with Postman or cURL to your POST route, and set up the route simply to console.log req.body to see if the data has reached the server.
### Views
- `index.ejs` should just be an unordered list of the Vampire's names. Each name should link to the `show` page for that Vamp. There should be a link to `add a new Vampire`.
- `show.ejs` should display the Vampire's name, location, gender, and number of victims. There should be a link to return to the Vampires index.
- `new.ejs` should render a form where the user can enter a new Vampire's name, location, gender, and number of victims. The form will submit to the `create` route.
### BONUS
- Make the app look nicer than just a plain html list. Use express.static('public') and integrate your css skills.
- Use jQuery on the frontend.

@ -0,0 +1,78 @@
module.exports = [
{
name: 'Count Chocula',
location: 'Minneapolis, Minnesota, US',
gender: 'm',
victims: 2
},{
name: 'Dracula',
location: 'Transylvania, Romania',
gender: 'm',
victims: 1238
},{
name: 'Elizabeth Bathory ',
location: 'Nyírbátor, Hungary',
gender: 'f',
victims: 980
},{
name: 'Lestat',
location: 'Auvergne, France',
gender: 'm',
victims: 324
},{
name: 'Louis de Pointe du Lac',
location: 'New Orleans, Louisiana, US',
gender:'m',
victims: 150
},{
name:'Claudia',
location: 'New Orleans, Louisiana, US',
gender: 'f',
victims: 290
},{
name:'Armand',
location: 'Kiev, Russia',
gender: 'm',
victims: 1045
},{
name:'Santino',
location: 'Rome, Italy',
gender: 'm',
victims: 1103
},{
name:'Akasha',
location: 'Kemet, Egypt',
gender: 'f',
victims: 210234,
},{
name: 'Edward Cullen',
location: 'Chicago, Illinois, US',
gender: 'm',
victims: 0
},{
name: 'Persephone Bourignon',
location: 'Paris, France',
gender: 'f',
victims: 450
},{
name: 'René Tremblay',
location: 'Bucharest, Romania',
gender: 'm',
victims: 134
},{
name: 'Caroline Belmont',
location: 'Ljubljana, Slovenia',
gender: 'f',
victims: 567
},{
name: 'Francis Frost',
location: 'New York, New York, US',
gender: 'm',
victims: 112
},{
name: 'Barnabas Spenser',
location: 'New York, New York, US',
gender: 'm',
victims: 0
}
];

@ -0,0 +1,17 @@
{
"name": "vampires_express_one_solution",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.14.2",
"ejs": "^2.4.1",
"express": "^4.13.4"
}
}

@ -0,0 +1,51 @@
var express = require('express'),
router = express.Router(),
Characters = require('../models/characters.js');
// INDEX
router.get('/', function(req, res) {
res.render('index.ejs', { data: Characters });
});
// NEW
// SHOW
router.get('/:id', function(req, res) {
for (var i=0; i < Characters.length; i++) {
if (Characters[i].id == req.params.id) {
res.render('show.ejs', { data: Characters[i] });
}
}
});
// EDIT
// CREATE
router.post('/', function(req, res) {
// code for assigning a new unique id
var max = -Infinity;
for( var i=0; i < Characters.length; i++) {
if( Characters[i].id > max) {
max = Characters[i].id
}
}
req.body.id = max + 1;
//^^ id assigned!
// more stuff needed here
});
// UPDATE
// remember to give req.body.id a value so that
// the character will be saved with an id
// DELETE
module.exports = router;

@ -0,0 +1,79 @@
# ADVENTURE TIME!
![](http://g3ar.co.za/wp-content/uploads/2014/05/Adventure-Time-The-Secret-of-the-Nameless-Kingdom-announced.png)
## App: Full CRUD and REST
Your mission is to make an Adventure Time character manager. Use the starter code provided. The app will:
- display a bunch of Adventure Time character images on the index
- have separate show pages for each character
- have the ability to add a new character
- have the ability to edit existing characters
- have the ability to delete characters
RESTful ROUTING:
- Index
- GET `/characters`
- Show
- GET `/characters/:id`
- New
- GET `/characters/new`
- Edit
- GET `/characters/:id/edit`
- Create
- POST `/characters`
- Update
- PUT `/characters/:id`
- Destroy
- DELETE `/characters/:id`
### Referencing by ID (not index)
Our Characters will be referenced by the id value within the characters' object. We will not
be referencing by index value any more because the index is outside the object, not within it.
```
Real databases reference by intrinsic ids, and we will be mimicking this in our app. We will be using a loop to retrieve the array element with the relevant id.
```
Each time you want to reference a specific Character object, you will need to loop over the Characters array. You will retrieve the record that matches the id from `req.params.id`.
When you create a new Character, it will be given a new **unique** id. Ids should be unique and persistent. If you delete the Character with id: 1, that id can never be used again. This ensures permanent identity within our individial Character objects.
The `create` route has a built in generator for assigning a new unique id.
### Method Override
The snippet for the method override middleware is already in the app. Method override is for submitting `PUT` and `DELETE` requests from the client. (Note: the purpose of method-override is to override the client's restriction of GET and POST requests only).
The tricky part is remembering all the stuff you need to put in your forms. Your `PUT` and `DELETE` forms will have an action of 'POST', but will have hidden inputs to hack the server to accept PUT or DELETE verbs.
```
<input type="hidden" name="_method" value="PUT">
```
### Notes on testing
Sometimes you don't want to have to build out a view or a form in order to test if a POST, PUT, or DELETE route is working. Use Postman or cURL on these routes and console.log a message and/or req.body to see if the route is working, and worry about the view later.
### Images
The Adventure Time character images are 300x300px. You can find 300x300px images on Google Images -> Search Tools -> Size -> Exactly . . .
### BONUS
Make it look and act nicely with static assets.
Try using jQuery to do stuff.

@ -0,0 +1,33 @@
module.exports = [
{
id: 1,
name: "Gunther",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=60472845",
about: "Gunter is the penguin that most commonly accompanies the Ice King. The Ice King uses Gunter as his personal servant, whereas the other penguins working for the Ice King are essentially slaves. In truth it is the ancient space being known as Orgalorg, who wishes to conquer the solar system."
}, {
id: 2,
name: "Earl of Lemongrab",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=55553952",
about: "The Earl of Lemongrab is the high-strung, overly-zealous, obnoxious, stubborn ruler of the Earldom of Lemongrab, and the heir to the Candy Kingdom. It is possible that he is no longer heir to the throne because as of 'Hot Diggity Doom' the Candy Kingdom is now a democracy.",
}, {
id: 3,
name: "Tree Trunks",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=55553801",
about: "After taking a bite out of the Crystal Gem Apple, Tree Trunks appears to mysteriously explode, but is later seen laughing and walking happily. It is later revealed that she had become the insane overlord of the Crystal Dimension. She tries to make Finn rule with her, but Finn and Jake defeat her knights and rescue her from her insanity. In 'Dream of Love,' Tree Trunks is in a romantic relationship with Mr. Pig.",
}, {
id: 4,
name: "Peppermint Butler",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=55553810",
about: "Peppermint Butler is a trusted member of Candy Kingdom society, but evidence suggests there is more to him than meets the eye. It is likely Peppermint Butler is more intelligent and able than he lets people believe. For example, in 'Mortal Recoil,' he realized that Princess Bubblegum was being possessed by the Lich, as evidenced by his hissing at the sight of her.",
}, {
id: 5,
name: "Marceline",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=68081426",
about: "Marceline Abadeer (full title: Marceline the Vampire Queen) is one of the main characters in Adventure Time and a half-demon/half-human, and vampire who is over 1003 years old.",
}, {
id: 6,
name: "Lumpy Space Princess",
img: "http://www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=36501503",
about: "Lumpy Space Princess (often referred to by her initials, LSP) is the princess of Lumpy Space. Finn and Jake have both traveled to Lumpy Space as well as to her parents' residence after she accidentally bit Jake in 'Trouble in Lumpy Space.' According to the events in 'Princess Day' she is not recognized by the chair of princesses, partially because her dramatic attitude and the fact that she is no longer the heir to Lumpy Space."
}
];

@ -0,0 +1,18 @@
{
"name": "adventure_time_express_solution",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.14.2",
"ejs": "^2.4.1",
"express": "^4.13.4",
"method-override": "^2.3.5"
}
}

@ -0,0 +1,30 @@
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
port = 3000 || process.env.PORT;
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride(function(req, res){
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
var method = req.body._method;
delete req.body._method;
return method;
}
}));
charactersController = require('./controllers/characters.js');
app.get('/', function(req, res) {
res.redirect('/characters');
});
app.use('/characters', charactersController);
app.listen(port, function() {
console.log('============================')
console.log('APP IS RUNNING ON PORT: ' + port);
console.log('============================');
});

@ -0,0 +1,21 @@
<html>
<head>
<title>Adventure Time</title>
</head>
<body>
<h1 style="font-family: monospace; display: inline-block">ADVENTURE TIME CHARACTERS</h1>
<a href="/characters/new" style="display: inline-block">Add new character</a>
</br>
<% for (var i=0; i < data.length; i++) { %>
<a href="characters/<%=data[i].id%>">
<img src="<%= data[i].img%>"/>
</a>
<% } %>
</body>
</html>

@ -0,0 +1,19 @@
<html>
<head>
<title>Adventure Time</title>
</head>
<body>
<div style="height: 500px; width: 500px; margin: 0 auto; text-align: center">
<a href="/characters">Back to list</a>
<h1><%= data.name %></h1>
<img src="<%= data.img %>"/>
<p><%= data.about %></p>
</div>
</body>
</html>

@ -0,0 +1,136 @@
{
name: 'Count Chocula',
hair_color: 'brown',
eye_color: 'brown',
dob: new Date(1971, 2, 13, 7, 47),
loves: ['cereal','marshmallows'],
location: 'Minneapolis, Minnesota, US',
gender: 'm',
victims: 2
},{
name: 'Dracula',
dob: new Date(937, 0, 24, 13, 0),
hair_color: 'brown',
eye_color: 'blue',
loves: ['Winona Ryder', 'top hats', 'fancy cloaks', 'handlebar mustaches'],
location: 'Transylvania, Romania',
gender: 'm',
victims: 1238
},{
name: 'Elizabeth Bathory ',
dob: new Date(1560, 8, 7, 22, 10),
hair_color: 'brown',
eye_color: 'brown',
loves: ['virgin blood', 'fancy cloaks','frilly collars'],
location: 'Nyírbátor, Hungary',
gender: 'f',
victims: 980
},{
name: 'Lestat',
dob: new Date(1760, 11, 9, 18, 44),
hair_color: 'blonde',
eye_color: 'blue',
loves: ['frilly shirtsleeves', 'frilly collars', 'lurking in rotting mansions', 'Louis'],
location: 'Auvergne, France',
gender: 'm',
victims: 324
},{
name: 'Louis de Pointe du Lac',
dob: new Date(1766, 6, 4, 2, 1),
hair_color: 'brown',
eye_color: 'blue',
loves:['brooding', 'Claudia', 'staring longingly into the distance'],
location: 'New Orleans, Louisiana, US',
gender:'m',
victims: 150
},{
name:'Claudia',
dob: new Date(1793, 2, 7, 8, 30),
hair_color: 'blonde',
eye_color: 'blue',
loves: ['doll babies', 'ribbons', 'appearing innocent', ' trickery'],
location: 'New Orleans, Louisiana, US',
gender: 'f',
victims: 290
},{
name:'Armand',
dob: new Date(1481, 6, 1, 10, 42),
hair_color: 'red',
eye_color: 'brown',
loves: ['theatre', 'painting', 'velvet robes', 'being tragic'],
location: 'Kiev, Russia',
gender: 'm',
victims: 1045
},{
name:'Santino',
dob: new Date(1465, 6, 1, 10, 42),
hair_color: 'brown',
eye_color: 'brown',
loves: ['trickery', 'vampiric cults', 'fancy cloaks'],
location: 'Rome, Italy',
gender: 'm',
victims: 1103
},{
name:'Akasha',
dob: new Date(-8000, 6, 1, 10, 42),
hair_color: 'brown',
eye_color: 'green',
loves: ['eating hearts', 'bathing in roses', 'elaborate headdresses', 'R&B music'],
location: 'Kemet, Egypt',
gender: 'f',
victims: 210234,
title: 'Queen of the Damned'
},{
name: 'Edward Cullen',
dob: new Date(1901, 6, 20, 0, 57),
hair_color: 'brown',
eye_color: 'brown',
loves: ['brooding', 'diamond skin', 'calling people spider monkeys'],
location: 'Chicago, Illinois, US',
gender: 'm',
},{
name: 'Persephone Bourignon',
dob: new Date(1801, 5, 17, 14, 53),
hair_color: 'red',
eye_color: 'green',
loves: ['wine', 'fancy cloaks', 'appearing innocent'],
location: 'Paris, France',
gender: 'f',
victims: 450
},{
name: 'René Tremblay',
dob: new Date(1922, 2, 8, 5, 3),
hair_color: 'brown',
eye_color: 'green',
loves: ['frilly shirtsleeves', 'trickery', 'card games'],
location: 'Bucharest, Romania',
gender: 'm',
victims: 134
},{
name: 'Caroline Belmont',
hair_color: 'blonde',
eye_color: 'brown',
dob: new Date(1799, 4, 21, 16, 15),
loves: ['marshmallows', 'ribbons', 'being tragic'],
location: 'Ljubljana, Slovenia',
gender: 'f',
victims: 567
},{
name: 'Francis Frost',
hair_color: 'black',
eye_color: 'blue',
dob: new Date(1976, 6, 18, 18, 18),
loves: ['brooding', 'frilly shirtsleeves'],
location: 'New York, New York, US',
gender: 'm',
victims: 112
},{
name: 'Barnabas Spenser',
hair_color: 'brown',
eye_color: 'brown',
dob: new Date(1984, 6, 3, 13, 12),
loves: ['being merry', 'being insane', 'card games'],
location: 'New York, New York, US',
gender: 'm',
title: 'Osiris of Sewer Rats'
}

@ -0,0 +1,159 @@
# Vampires!
![Interview with the Vampire](https://mischiefmanagedsite.files.wordpress.com/2014/05/3.gif)
### Setup
1. Start `mongod`
2. Open your mongo console with `mongo`. Note: This homework is done in the terminal, there is no Express.
3. Connect to a new database called `monsters` with `use monsters`
4. Using the js objects of vampires in `populateVampires.js`, add the vampires to a `vampires` collection. Hint: you can use the **Adding Losts of New Documents** syntax from the example at the bottom of this document.
### Resources
#### Utilize the following resources to research the commands you will need
[https://docs.mongodb.org/manual/reference/operator/query/#query-selectors]
[http://mongoosejs.com/]
## MONGO SELECTION COMMANDS
***For the following parts, write mongo queries in your CLI, and when you figure out the right answer, copy the correct mongo queries into a `selectVampires.md` file.***
### Part 1
#### Select by comparison
Select all the vampires that:
- have greater than 500 victims
- have fewer than or equal to 150 victims
- have a victim count is not equal to 210234
- have greater than 150 AND fewer than 500 victims
### Part 2
#### Select by exists or does not exist
Select all the vampires that:
- have a title property
- do not have a victims property
- have a title AND no victims
- have victims AND the victims they have are greater than 1000
### Part 3
#### Select objects that match one of several values
Select all the vampires that:
- love either `frilly shirtsleeves` or `frilly collars`
- love `brooding`
- love at least one of the following: `appearing innocent`, `trickery`, `lurking in rotting mansions`, `R&B music`
- love `fancy cloaks` but not if they also love either `top hats` or `virgin blood`
\* *Hint-You will also have to use $nin* \*
### Part 4
#### Select objects that match one of several values
Select all the vampires that:
- love either `frilly shirtsleeves` or `frilly collars`
- love `brooding`
- love at least one of the following: `appearing innocent`, `trickery`, `lurking in rotting mansions`, `R&B music`
- love `fancy cloaks` but not if they also love either `top hats` or `virgin blood`
\* *Hint-You will also have to use $nin* \*
### Part 5
#### Select with OR
Select all the vampires that:
- are from `New York, New York, US` or `New Orleans, Louisiana, US`
- love `brooding` or `being tragic`
- have more than 1000 victims or love `marshmallows`
- have red hair or green eyes
### Part 6
#### Negative Selection
Select all vampires that:
- love `ribbons` but do not have blonde hair
- are not from Rome
- do not love any of the following:
[`fancy cloaks`, `frilly shirtsleeves`, `appearing innocent`, `being tragic`, `brooding`]
- have not killed more than 200 people
### Part 7
#### Replacing a record
Replace the following:
- replace the vampire called 'Claudia' with a vampire called 'Eve'. 'Eve' will have a key called 'portrayed_by' with the value 'Tilda Swinton'
- replace the first male vampire with another whose name is 'Guy Man', and who has a key 'is_actually' with the value 'were-lizard'
### Part 8
#### Update single values
Update the following:
- Update 'Guy Man' to have a gender of 'm'
- Update 'Eve' to have a gender of 'f'
- Update 'Guy Man' to have an array called 'hates' that includes 'clothes' and 'jobs'
- Update 'Guy Man's' hates array also to include 'alarm clocks' and 'jackalopes'
- Rename 'Eve's' name field to 'moniker'
### Part 9
#### Remove documents
https://docs.mongodb.org/manual/tutorial/remove-documents/
- Remove a single document wherein the hair_color is 'brown'
- Remove all documents wheren the eye-color is 'green'
### Bonus
Make an express app and include Mongoose. Make a Mongoose schema for Items, populate the database with two items, then make an index route that will res.send the json for those items.
Extra bonus: Make a show route.
#### Adding Lots of New Documents in plain Mongo
Pretend we have a collection called `people` and want to add lots of documents, we can simply provide this __array__ to the _insert_ method and it will create a document for each object in the array.
```
[
{
"name": "Emma",
"age": 20
},
{
"name": "Ray",
"age": 45
},
{
"name": "Celeste",
"age": 33
},
{
"name": "Stacy",
"age": 53
},
{
"name": "Katie",
"age": 12
},
{
"name": "Adrian",
"age": 47
}
]
```
> Note: Be sure to type the closing parenthesis of the _insert_ method!
`db.people.insert([array])`

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

@ -0,0 +1,182 @@
# MONGOOSE STORE
Make a product inventory manager with full CRUD using Mongoose.
## APP
###Index page
Your app should have an index page where
- all the products are displayed
- the images link to the product's **show** page
- and there should be a link to add a new product.
![index](index.png)
###Show page
Your show page should display a product with
- a link back to the products
- a link to edit the product (goes to the edit page)
- a delete button that deletes
- and the number of items remaining in stock.
For the **Primary Bonus**: There will be a BUY button. The BUY button will reduce the number of items in stock by 1 each time it's pressed.
![show](show-stock.png)
![bins](bins.png)
If the quantity of your item is zero, the show page should say 'OUT OF STOCK' instead of saying how many are remaining. (Hint: `ejs`). On the edit page, make sure you can set the quantity to zero if you want so that you can test if this is working.
For the **Primary Bonus** the BUY button should also not be rendered.
![no-show](show-no-stock.png)
###Edit page and New page
These views should render forms and submit to the appropriate routes.
###Redirects:
- The *create* route should redirect to the index
- The *delete* route should redirect to the index
- The *update* route will redirect back to the product's **show** page.
- For the **Primary Bonus** the BUY button will go to a route that redirects back to the product's **show** page
### Directions
- Set up Express with MVC architecture
- You will need the seven RESTful routes to start. Test that they are accessible with Postman or cURL. Don't worry about what the BUY button does or where it goes just yet. Just set up your regular RESTful stuff.
- You will need to make a Mongoose Schema in a `products.js` file for your products. The schema should have:
```
name: String,
description: String,
img: String,
price: Number,
qty: Number
```
- Make sure you connect to your Mongo server
```
mongoose.connect('mongodb://localhost/mongoose_store');
// this works for me, but if you have some other config, check the class notes
```
- **If you have mongoose.connect in your file, Your Node server will crash if you aren't running `mongod`**
- Make sure your controller can access your model
```
var Product = require('../models/products');
```
For testing purposes, especially for having quick access to those wacky Mongo ids, maybe think about having a route `/json` that `res.sends` an index of all the data in json format so that you can copy/paste ids into your url bar or cURL or what-have-you.
###SEED
You can use these seeds to get starting data if you so choose. Handy hint: Make a route in your products controller `/seed/newproducts`, and to seed your database, just visit the route **once** in your browser.
```
router.get('/seed/newproducts', function(req, res) {
var newProducts = [
{
name: "Beans",
description: "A small pile of beans. Buy more beans for a big pile of beans.",
img: "http://www.allbulkfoods.com/images/catalog/419240.jpg",
price: 5,
qty: 99
}, {
name: "Bones",
description: "It's just a bag of bones.",
img: "http://bluelips.com/prod_images_large/bones1.jpg",
price: 25,
qty: 0
}, {
name: "Bins",
description: "A stack of colorful bins for your beans and bones.",
img: "http://www.clipartbest.com/cliparts/9cz/rMM/9czrMMBcE.jpeg",
price: 7000,
qty: 1
}
];
Product.create(newProducts, function(err) {
console.log("SEED: NEW PRODUCTS CREATED!");
res.redirect('/products');
});
});
```
# Mongoose commands - hints
###index
```
Product.find(function(err, products) {
console.log(products);
})
```
###show, edit
```
Product.findById(req.params.id, function(err, product) {
console.log(product);
});
```
###update
```
Product.findOneAndUpdate( { _id: req.params.id }, req.body, function(err, product) {
console.log(product);
});
```
###delete
```
Product.remove({ _id: req.params.id}, function(err) {
//
});
```
# PRIMARY BONUS
If a product is in stock (the qty is above 0), the **show** page should have a `BUY` button. If the product is out of stock, it should not have this button.
When the `BUY` button is pressed, it will make a request to update the qty of the product (decrease it by 1).
- What route should the `BUY` request go to?
- Since it `updates` the product, should it go to a `PUT` route?
- Do you need to send any data through to the route?
- Can you edit the qty value just in the route? `product.qty -= 1`?
- Will you have to `product.save()` if you do this?
- Should you use the already-existing `PUT` route, or can you make another?
- Just get it to work.
# *PRESIDENTIAL BONUS*
Make *another* model, this time for a User. The User will have:
```
username: String,
shopping_cart: Array
```
On the product **show** page, when a user presses `BUY`, the product will be added to the User's shopping cart.
View the shopping cart on the User's **show** page. (The User will need only a show page and none of the other routes).
To get more advanced with multiple models that reference each other, look up `subdocuments`, this will give you a head start for next week.
...

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

@ -0,0 +1,11 @@
var express = require('express'),
router = express.Router();
// INDEX
router.get('/', function(req, res) {
res.render('locations/index.ejs');
});
module.exports = router;

@ -0,0 +1,16 @@
var express = require('express'),
router = express.Router();
// INDEX
router.get('/', function(req, res) {
res.render('users/index.ejs')
});
// SHOW
router.get('/:id', function(req, res) {
res.render('users/show.ejs');
});
module.exports = router;

@ -0,0 +1,19 @@
{
"name": "maps_multiple_models",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.15.0",
"ejs": "^2.4.1",
"express": "^4.13.4",
"method-override": "^2.3.5",
"mongoose": "^4.4.3"
}
}

@ -0,0 +1,71 @@
body {
font-family: monospace;
background-color: ivory;
}
#header {
text-align: center;
}
#title {
font-size: 40px;
color: #E593E5;
}
#container {
width: 1400px; height: 850px;
margin: 0 auto;
}
#map-canvas {
height: 750px; width: 1000px;
display: inline-block;
margin-top: 5px;
border-radius: 15px;
}
#control-panel {
overflow: scroll;
display: inline-block;
height: 750px; width: 350px;
border-radius: 15px;
background-color: #D7D7FF;
text-align: center;
}
#users-title {
font-size: 25px;
}
#dataset-select-container {
height: 200px; width: 200px;
margin: 0 auto;
text-align: center;
margin-top: 30px;
}
#locations-container {
overflow: scroll;
width: 350px;
height: 480px;
}
.location {
margin: 0 auto;
height: 60px; width: 300px;
background-color: azure;
text-align: center;
border-radius: 8px;
font-size: 18px;
line-height: 60px;
vertical-align: middle;
}
#delete-button {
height: 40px; width: 90px;
border-radius:5px;
border: none;
background-color: black;
color: white;
cursor: pointer;
}

@ -0,0 +1,39 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
addMarkers(map);
} // end initialize
// Display the map
google.maps.event.addDomListener(window, 'load', initialize);
}); // end window onload
var addMarkers = function(map) {
//ajax call to get locations data from 'locations/json' route
$.ajax('/locations/json')
.done(function(result) {
// add location markers
for (var i=0; i < result.length; i++) {
marker = new google.maps.Marker ({
map: map,
icon: 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png',
position: { lat: result[i].lat, lng: result[i].lng },
title: result[i].name
});
};
});
} // end addMarkers

@ -0,0 +1,29 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// Add new markers
addMarkers(map);
} // end initialize
// Display the map
google.maps.event.addDomListener(window, 'load', initialize);
}); // end window onload
var addMarkers = function(map) {
// add markers biz
} // end addMarkers

@ -0,0 +1,24 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
} // end initialize
// DISPLAY THE MAP
google.maps.event.addDomListener(window, 'load', initialize);
// Event listener for drop-down menu .change
// redirects to show page
// >>
});

@ -0,0 +1,157 @@
# MAPS & MULTIPLE MODELS
```
- subdocuments and referencing between models
- program flow
- getting server data into static javascript files / Google Maps
```
## App
Pages:
- Users index
- Has a dropdown menu of all users. When the option is changed, the page goes to the user's show page
- Has a form for creating a new user
- redirects to new user's show page
- Has a link to see all locations
- Nothing on the map
![](usersindex.png)
- Locations index
- Has a list in the control panel of all locations from all users
- Displays all locations on a Google Map
- A link to see locations by user (users index)
![](locationsindex.png)
- Users show
- User's name is there
- Shows just this user's locations
- Has a form to add a new location for this user
- redirect back here to user's show page
- Has a delete button
- deletes user and associated locations. Deleted locations should not show up on the locations index.
![](usersshow.png)
## Data modeling
A user should have at minimum:
```
username: String
```
and a Location should have at minimum:
```
name: String,`
lat: Number,
lng: Number
```
But what else is needed to specify a relation between these two models in regards to our program flow? Answer: subdocuments, at least.
## Data, AJAX, and Static files
The Google Maps stuff is all front-end static JS. It is not constructed with input from the server or server-rendered templates. However, we want to get data on to the map, because each marker is positioned according to lat and lng values stored in the database.
How can we get server / database data into our static JS files?
In the locationsIndex.js file in the public folder, underneath the Maps setup there is a jQuery ajax call to get the data to put in the Markers. Ajax is a way to pull data from remote urls. In this case, we're just pulling our own data from our server. The ajax call is looking for JSON, so you will need to make a route that just serves up JSON, and the ajax will pick it up.
You may or may not want to use ajax on your user show page, too. However, you will need to get creative as to how your javascript file will get the user id for the route. There is a potential solution at the bottom of this page.
The most basic ajax command is:
```
$.ajax('/route').done(function(data) {
console.log(data);
});
```
`.done` is a `promise` that waits for the asynchronous call to be complete before passing the acquired data to the callback.
# BONUS
On the Locations index page, get the usernames to show for each associated location in the control panel.
### Seed Locations
You can get latitude and longitude from a (real) Google Map by right clicking (or control+click) on the map and selecting "what's here?". The lat and lng will show up. Click on the lat and lng for a copyable-pastable format.
Some seeds:
```
name: 'Prospect Park',
lat: 40.660301,
lng: -73.968977
```
```
name: 'Columbus Circle',
lat: 40.768280,
lng: -73.982351
```
```
name: 'General Assembly',
lat: 40.740047,
lng: -73.990092
```
```
name: 'Brooklyn Navy Yard',
lat: 40.699671,
lng: -73.973941
```
```
name: 'PS1',
lat: 40.745507,
lng: -73.946899
```
```
name: Starrett City,
lat: 40.650274,
lng: -73.883603
```
```
name: 'Flushing Meadows',
lat: 40.739762,
lng: -73.840828
```
```
name: 'Sumner Houses',
lat: 40.697482,
lng: -73.940075
```
///////
//////
/////
////
///
//
/
**Potential solution for getting user id into static JS AJAX call:**
*** Are you sure you don't want to find your own solution? ***
***Disclaimer: this is just one solution, you could do it other ways too***
**Answer**
Display the user id on the webpage. Hide it with css. Use JQuery to grab it.

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 KiB

@ -0,0 +1,35 @@
var express = require('express'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
mongoose = require('mongoose'),
port = 3000 || process.env.PORT,
app = express();
mongoose.connect('mongodb://localhost/maps_models');
var locationsController = require('./controllers/locationsController'),
usersController = require('./controllers/usersController');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride(function(req, res){
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
var method = req.body._method;
delete req.body._method;
return method;
}
}));
app.use('/locations', locationsController);
app.use('/users', usersController);
app.get('/', function(req, res) {
res.redirect('/users');
});
app.listen(port, function() {
console.log('Running on port ' + port);
});

@ -0,0 +1,26 @@
<html>
<head>
<title>Locations App</title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/locationsIndex.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<% include ../title_partial.ejs %>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/users"><p>Locations by user</p></a>
</div> <!-- end control-panel -->
</main>
</div>
</body>
</html>

@ -0,0 +1,42 @@
<html>
<head>
<title>Locations App</title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/usersIndex.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<% include ../title_partial.ejs %>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/locations"><p>All Locations</p></a>
<div id="dataset-select-container">
<p id="users-title">Users</p>
<select id="dataset-select">
<option value="no id"/>-------</option>
<!-- options for users -->
</select>
</div>
<p>Add a new user</p>
<form action="/users" method="POST">
<input type="text" name="username" placeholder="username">
<input type="submit">
</form>
</div> <!-- end control-panel -->
</main>
</div>
</body>
</html>

@ -0,0 +1,48 @@
<html>
<head>
<title>Locations App</title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/userShow.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<% include ../title_partial.ejs %>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/locations"><p>All locations</p></a>
<a href="/users"><p>Back to all users</p></a>
<p id="users-title">"Username's" locations</p>
<p>add a new location</p>
<form action="??" method="POST">
<input type="text" name="name" placeholder="name">
<input type="text" name="lat" placeholder="latitude">
<input type="text" name="lng" placeholder="longitude">
<input type="submit">
</form>
<div id="locations-container">
<!-- something -->
<div class="location">
<p>"Location 1"</p>
</div>
</div>
<form action="??" method="POST">
<input type="hidden" name="_method" value="DELETE">
<button id="delete-button">Delete User</button>
</form>
</div> <!-- end control-panel -->
</main>
</div>
</body>
</html>

@ -0,0 +1,84 @@
var User = require('../models/users');
var LocalStrategy = require('passport-local').Strategy;
module.exports = function(passport) {
console.log('passport config invoked');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =====================
// SIGNUP
// =====================
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function(req, email, password, done) {
console.log('Req.body within local signup: ', req.body);
User.findOne({ 'email': email }, function(err, user) {
if (err) { return done(err) }
if (user) {
return done(null, false);
} else {
var newUser = new User();
newUser.email = email;
newUser.password = newUser.generateHash(password);
newUser.username = req.body.username;
newUser.save(function(err) {
if (err) {
console.log(err)
throw err
} else {
return done(null, newUser);
}
}); // end user save
} // end user check exists
}) // end find user
} // end localstategy params
)); // end passport local signup
// =====================
// LOGIN
// =====================
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function(req, email, password, done) {
User.findOne({ 'email': email }, function(err, user) {
if (err) { return done(err) }
if (!user) {
console.log('NO USER FOUND');
return done(null, false);
}
if (!user.validPassword(password)) {
return done(null, false);
}
return done(null, user);
}); // end find user
} // end localstrategy params
)); // end passport local login
} // end module

@ -0,0 +1,32 @@
var express = require('express'),
router = express.Router();
var User = require('../models/users'),
Location = require('../models/locations');
// locations index
router.get('/', isLoggedIn, function(req, res) {
Location.find(function(err, locations) {
res.render('locations/index.ejs', { locations: locations });
});
});
// json for locations, fetched by ajax to display markers on map
router.get('/json', function(req, res) {
Location.find(function(err, location) {
res.send(location);
});
});
// middleware to check login status
// used in index route
function isLoggedIn(req, res, next) {
console.log('isLoggedIn middleware');
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/users');
}
}
module.exports = router;

@ -0,0 +1,104 @@
var express = require('express'),
passport = require('passport'),
router = express.Router();
var User = require('../models/users'),
Location = require('../models/locations');
// user index
router.get('/', function(req, res) {
res.locals.login = req.isAuthenticated();
User.find(function(err, users) {
res.render('users/index.ejs', { users: users });
});
});
// json for all users (for testing)
router.get('/json', function(req, res) {
User.find(function(err, users) {
res.send(users);
});
});
// json for specific user, fetched by ajax to display markers on map
router.get('/:id/json', function(req, res) {
User.findById(req.params.id, function(err, user) {
res.send(user);
});
});
// logout of session
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/users');
});
// show page -- can only be viewed if logged in
router.get('/:id', isLoggedIn, function(req, res) {
// for user control flow within template (enables editing only on the user's own page)
req.params.id == req.user.id ? res.locals.usertrue = true : res.locals.usertrue = false;
User.findById(req.params.id, function(err, user) {
res.render('users/show.ejs', { user: user });
});
});
// saves a new location to the Location model and the User's locations list
router.post('/:id/newlocation', function(req, res) {
User.findById(req.params.id, function(err, user) {
var location = new Location(req.body);
location.save(function(err, location) {
user.locations.push(location);
user.save(function(err, user) {
res.redirect('/users/' + req.params.id);
});
});
});
});
// user create -- signup
router.post('/', passport.authenticate('local-signup', {
failureRedirect: '/users' }), function(req, res) {
//success redirect goes to show page
res.redirect('/users/' + req.user.id);
});
// login
router.post('/login', passport.authenticate('local-login', {
failureRedirect: '/users' }), function(req, res) {
// success redirect goes to show page
res.redirect('/users/' + req.user.id);
});
// delete
router.delete('/:id', function(req, res) {
console.log('DELETE ROUTE ACCESSED');
User.findById(req.params.id, function(err, user) {
if (user.locations.length == 0) {
user.remove(function(err) {
res.redirect('/users');
});
} else {
user.locations.forEach(function(location) {
Location.findOneAndRemove({ _id: location.id }, function(err) {
if (err) console.log(err);
});
});
user.remove(function(err) {
res.redirect('/users');
});
} // end if
}); // end User find
});
// middleware to check login status
// used in show route
function isLoggedIn(req, res, next) {
console.log('isLoggedIn middleware');
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/users');
}
}
module.exports = router;

@ -0,0 +1,9 @@
var mongoose = require('mongoose');
var locationSchema = mongoose.Schema({
name: String,
lat: Number,
lng: Number
})
module.exports = mongoose.model('Location', locationSchema);

@ -0,0 +1,23 @@
var mongoose = require('mongoose');
var locationSchema = require('./locations').schema;
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema({
username: String,
email: String,
password: String,
locations: [locationSchema]
});
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
}
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.password);
}
module.exports = mongoose.model('User', userSchema);

@ -0,0 +1,23 @@
{
"name": "maps_multiple_models",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.15.0",
"ejs": "^2.4.1",
"express": "^4.13.4",
"express-session": "^1.13.0",
"method-override": "^2.3.5",
"mongoose": "^4.4.3",
"passport": "^0.3.2",
"passport-local": "^1.0.0"
}
}

@ -0,0 +1,78 @@
body {
font-family: monospace;
background-color: ivory;
}
#header {
text-align: center;
}
#title {
font-size: 40px;
color: #E593E5;
}
#container {
width: 1400px; height: 850px;
margin: 0 auto;
}
#map-canvas {
height: 750px; width: 1000px;
display: inline-block;
margin-top: 5px;
border-radius: 15px;
}
#control-panel {
overflow: hidden;
display: inline-block;
height: 750px; width: 350px;
border-radius: 15px;
background-color: #D7D7FF;
text-align: center;
}
#users-title {
font-size: 25px;
}
#dataset-select-container {
height: 200px; width: 200px;
margin: 0 auto;
text-align: center;
margin-top: 30px;
}
#locations-container {
overflow: scroll;
width: 350px;
height: 480px;
}
#all-locations-container {
overflow: scroll;
width: 350px;
height: 680px;
}
.location {
margin: 0 auto;
height: 60px; width: 300px;
background-color: azure;
text-align: center;
border-radius: 8px;
font-size: 18px;
line-height: 60px;
vertical-align: middle;
}
#delete-button {
height: 40px; width: 90px;
border-radius:5px;
border: none;
background-color: black;
color: white;
cursor: pointer;
}

@ -0,0 +1,38 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
addMarkers(map);
} // end initialize
// DISPLAY THE MAP
google.maps.event.addDomListener(window, 'load', initialize);
});
var addMarkers = function(map) {
//ajax call to get location data
$.ajax('/locations/json').
done(function(result) {
// add location markers
for (var i=0; i < result.length; i++) {
marker = new google.maps.Marker ({
map: map,
icon: 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png',
position: { lat: result[i].lat, lng: result[i].lng },
title: result[i].name
});
};
});
} // end addMarkers

@ -0,0 +1,41 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
// Add new markers
addMarkers(map);
} // end initialize
// DISPLAY THE MAP
google.maps.event.addDomListener(window, 'load', initialize);
});
var addMarkers = function(map) {
var userid = $('#user_id').text();
//ajax call to get location data
$.ajax('/users/' + userid + '/json').
done(function(result) {
// add location markers
for (var i=0; i < result.locations.length; i++) {
marker = new google.maps.Marker ({
map: map,
icon: 'http://maps.google.com/mapfiles/ms/icons/orange-dot.png',
position: { lat: result.locations[i].lat, lng: result.locations[i].lng },
title: result.locations[i].name
});
};
});
} // end addMarkers

@ -0,0 +1,25 @@
$(function() {
// Google Map Settings
var initialize = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 12,
minZoom: 10,
streetViewControl: false,
mapTypeControl: false,
center: new google.maps.LatLng(40.696829, -73.935232),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
} // end initialize
// DISPLAY THE MAP
google.maps.event.addDomListener(window, 'load', initialize);
// Event listener for drop-down menu change
$('#dataset-select').change(function(){
document.location.href="/users/" + $('#dataset-select').val();
});
});

@ -0,0 +1,57 @@
var express = require('express'),
bodyParser = require('body-parser'),
methodOverride = require('method-override'),
mongoose = require('mongoose'),
passport = require('passport'),
session = require('express-session'),
port = 3000 || process.env.PORT,
app = express();
mongoose.connect('mongodb://localhost/maps_auth_app');
// load passport config
require('./config/passport')(passport);
locationsController = require('./controllers/locationsController');
usersController = require('./controllers/usersController');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(session({ name: 'maps_auth_app', secret: 'conventional wisdom' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(methodOverride(function(req, res){
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
var method = req.body._method;
delete req.body._method;
return method;
}
}));
// Example middleware for template control flow via 'login' variable.
// I'm using res.locals.login = req.isAuthenticated() only in the users index controller for now,
// for use only in users/index.ejs view. I've commented it here in case I ever wanted to make it
// available to other pages or make it app-wide in future.
// app.use('/', function(req, res, next) {
// res.locals.login = req.isAuthenticated();
// next();
// });
app.use('/locations', locationsController);
app.use('/users', usersController);
// root redirects to users index
app.get('/', function(req, res) {
res.redirect('/users');
});
app.listen(port, function() {
console.log('=======================');
console.log('Running on port ' + port);
console.log('=======================');
});

@ -0,0 +1,35 @@
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/app.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<h1 id="title">THESE ARE LOCATIONS</h1>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/users"><p>Locations by user</p></a>
<div id="all-locations-container">
<% for (var i=0; i < locations.length; i++) { %>
<div class="location">
<p><%= locations[i].name %></p>
</div>
<% } %>
</div>
</div>
</main>
</div>
</body>
</html>

@ -0,0 +1,70 @@
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/users.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<h1 id="title">THESE ARE LOCATIONS</h1>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/locations"><p>All Locations</p></a>
<div id="dataset-select-container">
<p id="users-title">Users</p>
<select id="dataset-select">
<option value=""/>-------</option>
<% for (var i=0; i < users.length; i ++) { %>
<option value="<%= users[i].id %>"><%= users[i].username %></option>
<% } %>
</select>
</div>
<% if (!login) { %>
<h2>You need to login or signup to continue</h2>
<% } %>
<% if (!login) { %>
<h4>Sign up</h4>
<form action="/users" method="POST">
<input type="text" name="username" placeholder="username">
<input type="text" name="email" placeholder="email">
<input type="text" name="password" placeholder="password">
<input type="submit">
</form>
<br/>
<br/>
<h4>Log in</h4>
<form action="/users/login" method="POST">
<input type="text" name="email" placeholder="email">
<input type="text" name="password" placeholder="password">
<input type="submit">
</form>
</br>
</br>
<% } else { %>
<a href="/users/logout"><p>Logout</p></a>
<% } %>
</div>
</main>
</div>
</body>
</html>

@ -0,0 +1,53 @@
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script type="text/javascript" src="/js/show.js"></script>
</head>
<body>
<p id="user_id" style="display: none"><%= user.id %></p>
<div id="container">
<div id="header">
<h1 id="title">THESE ARE LOCATIONS</h1>
</div>
<main>
<div id="map-canvas"></div>
<div id="control-panel">
<a href="/locations"><p>All locations</p></a>
<a href="/users"><p>Back to all users</p></a>
<p id="users-title"><%= user.username %>'s locations</p>
<% if (usertrue) { %>
<p>add a new location</p>
<form action="/users/<%= user.id %>/newlocation" method="POST">
<input type="text" name="name" placeholder="name">
<input type="text" name="lat" placeholder="latitude">
<input type="text" name="lng" placeholder="longitude">
<input type="submit">
</form>
<% } %>
<div id="locations-container">
<% for (var i=0; i < user.locations.length; i++) { %>
<div class="location">
<p><%= user.locations[i].name %></p>
</div>
<% } %>
</div>
<% if (usertrue) { %>
<form action="/users/<%= user.id %>" method="POST">
<input type="hidden" name="_method" value="DELETE">
<button id="delete-button">Delete Self</button>
</form>
<% } %>
</div>
</main>
</div>
</body>
</html>

@ -6,12 +6,15 @@ $(function() {
var $startShuffle = $('#start-shuffle');
var $message = $('#message');
// declare globally available variables
var gamesPlayed = 0;
var wins = 0;
var randomBrain;
var state;
// resets the board
var reset = function() {
state = "start";
$startShuffle.text("START");
@ -31,6 +34,8 @@ $(function() {
// run the reset function on window onload
reset();
// determines which function to run when the start button is clicked,
// depending on the state of the game
$startShuffle.click(function() {
if (state === "start") {
giveIdea();
@ -42,6 +47,7 @@ $(function() {
}
});
// selects a random brain and gives it an idea
var giveIdea = function() {
randomBrain = Math.floor(Math.random() * 5);
$('#' + randomBrain).html('<img src="brainlight.png"/>');
@ -51,7 +57,7 @@ $(function() {
state = "shuffle";
}
// run recursively according to the counter, to repeat animations
// runs recursively according to the counter, to repeat animations
var counter = 0;
var shuffleBrains = function() {
@ -64,6 +70,7 @@ $(function() {
$('#' + index + ' img').css({ animationName: 'brainsize' });
});
// invokes this function recursively
var brainLoop = setTimeout(shuffleBrains, 501);
counter++;
@ -78,6 +85,7 @@ $(function() {
}
}
// checks for a winner
var checkBrain = function() {
if ($(this).is('#' + randomBrain)) {
$('#message').text("THIS IS THE BRAIN!!!");

@ -6,7 +6,7 @@ body {
width: 800px;
height: 440px;
border: 1px solid black;
margin: 0 auto;
margin-left: 120px;
border-radius: 15px;
background-color: ivory;
}
Loading…
Cancel
Save