diff --git a/web/README.md b/web/README.md index 76912a2..7fe00b2 100644 --- a/web/README.md +++ b/web/README.md @@ -1 +1,83 @@ # Web + +## What you'll make +A very simple project showcase complete with its own comment section! + +## What you'll learn +An introduction to: + HTML, CSS, Javascript, JQuery, your first web framework (Flask), Python (again Flask), a templating engine, working with databases, and deploying to Heroku! + + +## What you'll need + +- A text editor +- Github, Git (Optional) + +## Table of Contents + +## Setup +A folder for your files to go in, and your favourite text editor (eg. Atom) + +### I'm just starting +// Instructions for setting up the environment for a complete beginner (e.g. download the Arduino IDE) + +Download the Atom text editor from https://atom.io/ + +### I've got some experience +// Instructions for intermediate learners (e.g. downloading certain libraries) + +## Vocabulary +// Glossary of technical terms used in the lesson plan + +- Servers, clients, front-end/back-end +- Server-side +- Client-side +- HTML, CSS, Javascript, PHP +- DOM +- dynamic vs static + +### Quick Overview + +#### How websites work +[just point form notes right now] +- HTML - structure +- CSS - styling +- JS - interactivity +- PHP (for example) - server-side logic +- server client model + +## Instructions +// Step-by-step instructions for building the core MVP + +1. Install Git +1. Make a basic website with HTML +2. Add styles with CSS +1. Meet the Chrome DevTools Inspector +3. Lay out a list of elements with CSS +4. Adding interactivity with JS - make a button +5. Implementing server-side logic with PHP - make a form +5. (Security) + +## Next Steps +// Less specific descriptions of additional features the learners should implement on their own + +- Create a landing page +- Add animations +- Make a scrolling menu bar +- Add post categories +- Create a "like" button +- List posts from one category only + +## Extend it further +// Bullet point ideas to inspire learners to extend & personalize their projects + +- Add a carousel to display top posts +- Make it public with Heroku +- Save user data +- Make posts searchable +- Create user accounts +- Use a web framework + +## Additional Resources +- For a fun CSS primer, check out http://flukeout.github.io/ +- [Google Fonts](https://www.google.com/fonts) diff --git a/web/css_snapshot_1.css b/web/css_snapshot_1.css new file mode 100644 index 0000000..7931e88 --- /dev/null +++ b/web/css_snapshot_1.css @@ -0,0 +1,10 @@ +body { + font-family: "Montserrat"; + color: white; + background-image: url("http://kriswhitewrites.com/wp-content/uploads/2013/06/landscape-mountains-snow-sky.jpg"); +} + +.post p { + font-family: "Open Sans"; + /*font-weight: 300;*/ +} diff --git a/web/html_dissected.png b/web/html_dissected.png new file mode 100644 index 0000000..67eb087 Binary files /dev/null and b/web/html_dissected.png differ diff --git a/web/html_snapshot_0.html b/web/html_snapshot_0.html new file mode 100644 index 0000000..0f858da --- /dev/null +++ b/web/html_snapshot_0.html @@ -0,0 +1,23 @@ + + + + + My First Tab Name + + +

My First Website Heading

+

My first paragraph

+
+

Project 1

+

My First Website

+
+
+

Project 2

+

My Second Website

+
+
+

Project 3

+

My Third Website

+
+ + diff --git a/web/html_snapshot_1.html b/web/html_snapshot_1.html new file mode 100644 index 0000000..0f5c146 --- /dev/null +++ b/web/html_snapshot_1.html @@ -0,0 +1,28 @@ + + + + + + + My First Tab Name + + + + + +

My First Website Heading

+

My first paragraph

+
+

Project 1

+

My First Website

+
+
+

Project 2

+

My Second Website

+
+
+

Project 3

+

My Third Website

+
+ + diff --git a/web/parts.md b/web/parts.md new file mode 100644 index 0000000..cfc51a1 --- /dev/null +++ b/web/parts.md @@ -0,0 +1,33 @@ +// temporary file + +### HyperText Markup Language (HTML) +Make your website outline (title, headings, a few words) + +The Document Object Model + +#### Tags +- `h1`, `a`, `div`, `span`, `p`, etc. + +### Cascading Style Sheets (CSS) + +#### The Basics +2016-ify all the things +- font, color, margin, padding +- [to be edited] + +### Cascading Style Sheets - the CSSequel +because we never go out of style ♫ + +#### Lorem Ipsum +// Add in your own sample projects/articles/etc, or use our [xtreme hi-tech generator](lorem ipsum) +// also high-Q pictures and icons (glyphicons) + +#### Layouts +- Grid +- List + +### Interacting With User Input + +#### Javascript +#### Forms +#### PHP diff --git a/web/web_lesson_0.md b/web/web_lesson_0.md new file mode 100644 index 0000000..e07ed1e --- /dev/null +++ b/web/web_lesson_0.md @@ -0,0 +1,554 @@ +## Hello, World (Wide Web) + +Long, long ago, when the great Tim-Berners Lee brought us the WWW, websites were documents that lived on some machine somewhere. Those documents had names called URLs by which anyone from anywhere across the world could request the document. The machine that hosted those documents would then 'serve' the document over the Internet to the person that had requested it. + +This anyone from anywhere across the world was called the `client`, +and the some machine somewhere that serves web resources like documents is known as the `server`. + + + +And that brings us to... + +## Your First Website + +Create a folder on your computer for all your files to go inside. +In Atom, create a new untitled file (File > New File) and save it as "index.html" in the folder you just created. + +Inside `index.html`, type: + +```html + + + + + My First Tab Name + + +

My First Website Heading

+

My first paragraph

+ + +``` + +Now go to Documents (Windows) / Finder (Mac) > "Open `index.html` in Chrome". + +You should see your very first website! + +## Welcome to HTML +HTML, or Hypertext Markup Language, defines the basic structure and content of every website. + +### Basic structure of an HTML Document + +![alt text](html_dissected.png "Boring alt text for an image of a labelled HTML document") + +### <h2>Elements, Tags, and Attributes</h2> + +To define the structure of a website, HTML uses tags: +```html +stuff that goes inside +``` +This is an HTML element. + +HTML follows grammar rules, which in programming we call `syntax` rules. +Tags pretty much always occur in pairs: an opening tag followed by a closing tag. (Except `
`, which is a line break.) +We'll see shortly that tags can be "nested" inside one another to contain each other. + +Aside from the tags shown here, we also have `div`. A `div` element is used as an all-purpose container. +Let's list a couple projects! +Add the following below the line for your first paragraph: +```html +
+

Project 1

+

My First Website

+
+
+

Project 2

+

My Second Website

+
+
+

Project 3

+

My Third Website

+
+``` +Notice the new `class="project"`. + +HTML elements can have `attributes` to describe them. Each attribute consists of a `name` and a `value`. +For example, "class" is an attribute with name "class" and its value in the HTML elements we just defined is "project". +The `class` attribute lets us group related elements together so we can do the same things on all of them. + +The `id` attribute is used to name a unique element. + +Here's what your HTML file should look like now: [html file](html_snapshot_0.html) + +## CSS Beauty Makeover + +Create a new file "File > New File" and name it "styles.css". Save it in the same folder as "index.html". + +Inside the new file, put: +```css +body { + font-family: "Helvetica"; +} + +h1 { + color: blue; + font-size: 40pt; +} + +.project { + background-color: orange; +} +``` + +Now tell the HTML file to use your new CSS file by updating the head to this: +```html + + + My First Tab Name + + +``` + +Refresh the page! You should see a slightly more colorful webpage now. + +### Language #2: CSS +CSS stands for Cascading Style Sheets. CSS files are what set the appearance of a website, from the font color of the text to the positions of each element. + +Now let's get into the real makeover. + +### We Never Go Out Of Style + +Take a look at this final CSS file: + +```css + +body { + font-family: "Montserrat"; +} + +.post p { + font-family: "Open Sans"; + /*font-weight: 300;*/ +} + +/*img { + height: 700px; + width: 500px; +}*/ + +/*h1 { + color: #006AFF; + color: white; +}*/ + +.navbar { + /*background-color: rgba(255, 255, 255, 0.1);*/ + padding: 5px; + /*#C2EAFF;*/ + height: 20px; + width: 70%; + margin: 0 auto 40px auto; +} + +.navbar ul { + margin: 0; +} + +.navbar ul li { + padding: 2px 3px; + margin: 0 30px 0 0; + /*change to nav not .navbar*/ + display: list-item; + list-style-type: none; + float: left; +} + +#current { + /*border: solid 1px #006AFF; + border-radius: 4px;*/ + border-bottom: solid 2px white; +} + +.navbar ul li a { + /*color: #006AFF;*/ + color: white; + float: left; +} + +.navbar ul { + padding: 0px; + /*display: list-item;*/ + /*list-style-type: none;*/ +} + +.navbar li { + float: left; + margin: 0 10px 0 0; +} + +.navbar ul li a { + text-decoration: none; +} + +.project { + opacity: 1; + transition: all 0.1s; + border: solid 1px white; + border-radius: 10px; + padding: 0 10px; + margin: 3px 3px; + width: 30%; + min-width: 150px; + float: left; + min-height: 125px; + position:relative; +} + +.project:hover { + background-color: rgba(255, 255, 255, 0.2); + transition: background-color 0.1s; +} + +/*Better solution to clickable div http://jsfiddle.net/hf75B/1/*/ +.link-spanner{ + position:absolute; + width:100%; + height:100%; + top:0; + left: 0; + z-index: 1; +} + +.fading { + opacity: 0; + border: solid 1px white; + border-radius: 10px; + padding: 0 10px; + margin: 3px 3px; + width: 30%; + min-width: 150px; + float: left; +} + +#container { + margin: auto; + width: 70%; + position: relative; +} + +.add { + position: absolute; + right: 0px; + font-size: 15pt; + z-index: 2; + /*background: none; + border: none;*/ +} + +#title { + padding: 100px; + text-align: center; + /*text-transform: uppercase;*/ + font-family: "Montserrat"; + font-size: 40pt; +} +/* +#footer { + position: fixed; + bottom: 0; + width: 100%; + height: 700px; +}*/ + +/*.add:active { + color: blue; +}*/ + +.list-hover-slide>li { + position: relative; + overflow: hidden; +} +.list-hover-slide>li>a { + z-index: 1; + transition: .35s ease color; +} +.list-hover-slide>li>a:before, .list-hover-slide>li.dropdown.open>a:before { + content:''; + display: block; + z-index: -1; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + transform: translateX(-100%); + border-right: solid 5px tomato; + background: gray; + transition: .35s ease transform; +} +.list-hover-slide>li>a:hover:before, .list-hover-slide>li.dropdown.open>a:before { + transform: translateX(0); +} +.list-hover-slide>li.dropdown.open { + overflow: initial; +} + +body { + width: 100%; + color: white; + background-color: #303030; + background-image: url("image.jpg"); + /*background-image: url("http://kriswhitewrites.com/wp-content/uploads/2013/06/landscape-mountains-snow-sky.jpg");*/ + /*background-size: cover;*/ + background-size: 100% 800px; + background-repeat: no-repeat; +} + +.post { + background-color: white; + color: #5E5E5E; + border-radius: 20px; + padding: 20px; + margin-bottom: 40px; +} + + .post h1 { + text-align: center; + /*color: gray;*/ + } + + a { + color: inherit; /* blue colors for links too */ + text-decoration: inherit; /* no underline */ +} + +input, textarea { + border: solid 1px #CCCCCC; + margin-bottom: 15px; + font-family: "Montserrat"; + /*background-color: gray;*/ +} + +textarea { + width: 100%; + box-sizing: border-box; +} + +#thread .poster:after { + content: " said:"; + font-family: "Open Sans"; + font-weight: 300; +} + +#thread .comment { + margin-bottom: 30px; +} + +#thread .poster { + margin-bottom: 10px; + color: gray; +} + +#thread .comment-text { + border-left: solid 3px tomato; + color: #5E5E5E; + padding-left: 15px; +} + +.like img { + /*background-image: url("heart-green.svg");*/ + width: 20px; + height: 20px; + display: inline; +} + +.like { + /*width: 40px;*/ + /*position: relative;*/ + display: inline; + float: right; +} + +.like p { + display: inline; + vertical-align: top; + padding-left: 5px; + line-height: 20px; + color: gray; +} + +`` +[TODO: update this css file] + +### Selectors +In the previous file: +- . selects all elements with class "something" +- \# selects the element with id "something" +- selects all elements with tag "something" +- selects all elements matching "another selector" that are __descendants__ of an element matching "some selector" +- __>__ selects all elements matching "another selector" that are __immediate children__ of an element matching "some selector" [(see relevant Stack Overflow answer)](http://stackoverflow.com/a/746557/5391146) +(You can check out http://flukeout.github.io/ for a fun CSS primer!) + +For now, replace the previous CSS code with this: +```css +body { + font-family: "Montserrat"; +} + +.post p { + font-family: "Open Sans"; +} +``` + +You'll need to add two more lines to your HTML head in order to use the fonts "Montserrat" and "Open Sans", so that the head looks like this: +[TODO: should it be in head?] +```html + + +``` +These were found using [Google Fonts](https://www.google.com/fonts). + +Change up the text in your HTML elements to fit the website, too. + +Let's add a background image! +Set the background image for `body` using +``` + background-image: url("http://kriswhitewrites.com/wp-content/uploads/2013/06/landscape-mountains-snow-sky.jpg"); +``` +Now make all the font white. (Hint: use the "color" attribute and "body" selector.) + +Using the above file as a reference, modify your current CSS file. +[Here's an example updated CSS file.](css_snapshot_1.css) + +## Adding interactivity with Javascript (not Java!) + +Javascript is a programming language that's recently taken the developer world by storm (There's Angular JS, Node JS, React JS, Meteor JS, Ember, Backbone, ... the list goes on). + + + +Here, we're going to use Javascript to make a clickable button for adding new projects. +Create a third file called "scripts.js". + + +### Manipulating the DOM + +Of course, the world isn't powered by many code monkeys modifying the HTML every time someone adds a new comment or post. + + + +Computer scientists and programmers are fanciful people. The Document Object Model is one example of a `tree` of `nodes`. A node can be a `root`. Otherwise, it has ancestors, and specifically, `parents`. A node can also have `children`, unless it's a `leaf`. + +You can modify the DOM tree `dynamically` with the web's favourite language - Javascript - using methods named after the terms we just described, like `.appendChild`. [edit] + +`.createElement` +`.appendChild` +`.getElementById` +`.getElementsByClass` +etc. + +Remember this keyword, `dynamic`, especially when searching StackOverflow - eg. "jQuery on click event not working for dynamically created items". + + + +## Fleshing out the website + +Let's start filling in the content. + +__Task 2:__ Turn each of the project divs into a clickable link to an HTML template titled `project_.html` (eg. "project_1.html"). + +__Task 2.5:__ the Navbar and About page + +__Task 3:__ Your turn now: Fill in `project_1.html`! + +## The Comment Thread + +Every good post has a place for its audience to discuss the post. [edit: rephrase] + +Whether it's a contact form so loving employers can drop you a line or a submission form for content, HTML has an element just for forms:
. [edit: rephrase] + +Example usage: +```html +
+ +
+ +
+ +
+ + + +
+``` +(edit: maybe don't give the exact code) + +__Task 4:__ Now edit the `script.js` file. Manipulate the DOM so that Internet users can add comments to your site dynamically. +To do this, you'll want to write the functions `addComment`, and `bind` the `submit` action for the `#comment-form` to code that calls `addComment`. +You can get the values stored in the HTML form's `fields` with `.val()`. +Remember that JQuery provides convenient selectors, so if your HTML input element has the id `#foo`, you can get its value with `$("#foo").val()`. + +### Good form (no pun intended) + +Here's an example final implementation: +```javascript +$("#comment-form").on("submit", function(e) { + e.preventDefault(); + var name = $("#name").val(); + $("#name").val(""); + var comment = $("#textarea").val(); + $("#textarea").val("comment here"); + if(validate(name) && validate(comment)) + addComment(name, comment); +}); +``` + +Notice the additional function `validate`. This is important! +Source: relevant xkcd comic. (little bobby tables) + +Try this: put the below input into the comment field (you can just leave the name field blank) +```javascript +TODO! +fill_me_in() +``` + +Real-life production code should never allow this, or else users could ~~take advantage of this security flaw to~~ run malicious scripts. + +### Animations and Effects with HTML and CSS and Javascript and JQuery + + + +## Sorry + +When you reload your page, all the comments disappear. All the posts you added disappear. Not even Ctrl+S can _save_ you. + +Unfortunately, this is the end for My First Website 2.0. + +What we're missing is a `database`. This is a persistent storage that lives elsewhere. Every time someone creates a new comment or post, this information is stored in the database and loaded up again when a user loads the website. + +Web apps really have three layers: + +- the presentation layer +- the + +[edit below section] +You could use PHP, which is a `server-side` `scripting` language. But goal #2 of this learnathon is to get you started with web development in 2016, and introduce you to web frameworks. + +And anyway, + +This is why developers use `web frameworks`, like Django, Ruby on Rails, Flask, + +## Recap + +HTML +CSS +Javascript + +## Onto Flask! diff --git a/web/web_lesson_1.md b/web/web_lesson_1.md new file mode 100644 index 0000000..d82e21b --- /dev/null +++ b/web/web_lesson_1.md @@ -0,0 +1,514 @@ +## Your First Flask Website + +Flask is a web framework that lets you write web apps in Python. We still use HTML, CSS, and Javascript, but a lot of the rest of the work is done in Python and there are now Python tools to simplify web development, like the Python templating engine Jinja2. + +#### Installs +To avoid interfering with your __local__ Python setup, it would be a good idea to install `virtualenv` (short for "virtual environment"). This is so that everything we mess around with relating to Python is contained inside of today's project. + +Once you've downloaded `virtualenv`, run the following command to create a new virtual environment in your current directory: + +###### Windows + + +###### Macs + +###### Linux + +Now to install Flask. You can install it [here](). + +This is also a good time to install PostgreSQL. +Install Flask-Migrate with pip install Flask-Migrate + +### Initial commit + + +Flask requires some basic setup files. + +_app.py_: +```python +from flask import Flask +app = Flask(__name__) + +@app.route('/') +def hello(): + return "Hello World!" + +if __name__ == '__main__': + app.run() +``` + +_requirements.txt_: +```text +Flask==0.10.1 +gunicorn==19.4.5 +``` + +_runtime.txt_: +``` +python-3.4.2 +``` + +__Protip__: Notice that the following file doesn't have any extension. +You can create files through your command prompt / terminal with the command `touch .` + +eg. +`touch Procfile` + +You can also edit files in the `command line` with one of the pre-installed editors like `emacs`, `vim`. + +eg. + +``` +vim Procfile +I +web: gunicorn app:app +Esc +X +``` + +You can see the contents of the file now with `cat Procfile`. + + +_Procfile_: +``` +web: gunicorn app:app +``` + +To see this website in your browser, run +`python app.py` in the terminal. + +This tells python to run the file `app.py`. +Now the last two lines in `app.py` come into play, because `app.py` is the main file running right now, so `app.run()` is called and the app is run. + + + +##### Checkpoint! + +Save your progress so far with +``` +git init +git add . +git commit -m "Initial commit" +``` + +## The Move to Flask + +It's time to translate our previous website to a Flask app. + +Copy over all the files we had before. +If you rerun the website now (TODO: can refresh?), you won't see any changes because Flask doesn't know about the files you just added. They're just sitting in the same directory. +To tell Flask to `serve` the `index.html` file and other files, you'll need to work with Flask's routes. + +### Routing + +All of this happens in `app.py`. +The [TODO] function can return text, like `return "Hello world!"` earlier. It can also return an HTML template, using the package `render_template`. + +Include `render_template` by changing the first line of `app.py` to: +```python +from flask import Flask, render_template +``` + +Here's a route: + +```python +@app.route('/') +def hello(): + return render_template(".html") +``` + +__Task 1__: Route the url '/' to index.html, and route the url '/about' to about.html. [TODO: methods] + +(Ruby on Rails uses routing, too.) + +### Templating Engines + +Now instead of `hardcoding` the url links in your HTML templates, you use the `url_for()` method to get the right url. +This way, certain [TODO: specify] changes you make in the future won't break anything, because `url_for()` will just return the new url. + +`url_for` works by going off of a standard structure for your app. All of the HTML templates go in a folder called templates. + +Here's what a basic project structure looks like: + +``` +/yourapplication + /yourapplication.py + /static + /style.css + /templates + layout.html + index.html + login.html + ... +``` +source: + +Images, JS (Javascript) files, and CSS stylesheets are `static`: the files themselves don't change when the website is run. +HTML goes under templates, since it lays out the basic structure. It's then served to the `client` (a user's local computer), then modified to bring it to what it should look like, and then possibly further modified as users interact with the website. + +### Rerun of the client server model + +### Back to routing + +Jinja2, the templating engine that comes with Flask, lets you write some useful Python code. +Any Python code inside an HTML template is specified with double curly brackets `{{}}`. +Now you can call `url_for()`. + +Here's an example of what the link to `scripts.js` should now look like: +```html + +``` + +Try rerunning your website with `python app.py`. The `console` will give you hints if things go wrong: a 404 file not found (TODO: get details on what console output looks like) means your url might not have been updated properly. The console will also tell you where the error occurred so you can find it. + +###### Testing - Houston, we have a problem + +In general, software development is accompanied with testing. Eg. `unit tests` will check that one part is working properly, while `regression tests` make sure that any new changes you made didn't break the old stuff. +For an example of what implementing +There's even `test driven development (TDD)`, where you write the test cases first and then write the minimal code to pass the tests. +Testing is great and makes you look less like a mad coder that hacks maniacally through the night on 50 cups of caffeine whose project is secretly ridden with bugs under the hood. [edit phrasing] + +##### Images, Glyphicons, and SVGs + + + +[TODO: use mouseenter] +```javascript +$(document).on("mouseenter", "img", function(event){ + $( this ).attr("src", "/static/heart-green-filled.svg"); +}).on("mouseleave", "img", function(event){ + $( this ).attr("src", "/static/heart-green.svg"); +}); +``` + +## Fancy Routing and Templating + +You can organize all your HTML templates by putting the project templates into their own subdirectory, so the project structure now looks like this: + +``` +/yourapplication + /static + heart.svg + heart-filled.svg + script.js + styles.css + /templates + /project + 1.html + 2.html + index.html + app.py + Procfile + requirements.txt + runtime.txt +``` + +Now for the slick part: dynamic routing. + +```python +@app.route('/project/', methods=['GET', 'POST']) +def asdf(id): + # return "/project/_"+id+".html" + comments = Comment.query.all() + return render_template("/project/"+id+".html", comments=comments) +``` + + +#### AJAX, the HTTP REST Protocol, GET, POST, and more + +The comment form no longer works. +You might have seen this message in the console when trying to submit a comment: + +```html +get output message +``` + +When a user submits a form, this POSTs the information to your website in the form of a POST request. +The default method allowed when routing is [TODO]. + +To fix this, specify the methods in a route like so: + +```python +@app.route('/my_url', methods=['GET', 'POST']) +``` + +## Heroku + +So far, your website can only be viewed on your computer. So much for "web"site. :( Now that it's a Flask app, we can put our app on __Heroku__. + +Heroku is a Platform as a Service (PaaS) - aka it provides hosting for web apps. + +Normally, you need to purchase a `domain` and [elaborate]. + +We also had another option before, which is Github Pages. This is free but it's only for `static` sites and not web applications. It's a good option to keep in mind though, eg. for a personal website! + +Anyways (and most importantly), Heroku provides free hosting (for up to five web apps, and the websites can't be running all the time, but hey, free hosting). + +Here's the link to create a Heroku account (). + + + +Once you've created a new app in the Heroku dashboard, you should select the app, navigate over to the __Deploy__ tab, and choose __Github__ as the __Deployment method__. + +From there, you can type in your Github repository name into the input field and connect your new Heroku app to the repository. + +If you now go to Settings, you can find the url for your app. + +## Databases + +A database stores information, although how it stores data varies. + +Just like there are many programming languages, there are a couple `database management systems`. Some examples are MySQL, SQLite, PostgreSQL, MongoDB, Oracle. + +There are three (two?) main camps: `relational` databases, `object-oriented` databases, and `NoSQL`. [TODO: fact check!] + +Relational databases are really the main type of database. Virtually all relational database management systems (`RDBMSs`) use `SQL` as their language, which is why so many of the examples given had 'SQL' in their name. +(As you can guess from the lack of 'SQL' in the name, MongoDB isn't an RDBMS.) + +We'll be using PostgreSQL, which is actually in between a `object-oriented` DBMS and a `relational` DBMS. (It's an `object-relational` DBMS, or, `ORDBMS`.) + +A relational database stores the data in `tables` of `rows` and `columns`: +- every column is a field +- every row is another data entry + +An object-oriented database stores data as `objects`. + + + +`SQL` stands for `Structured Query Language`, because you do two things with a database: store information in a database, and `query` the database to get its information. + +A SQL query looks something like the following: + +```sql +SELECT * AS older_customers FROM customer_table WHERE age > 20 +``` +> this means select all "customers" (technically these are data entries in the database and not actual people) over the age of 20, and call this selection of customers "older_customers". + +Note: the web app won't use SQL because there's a Python package called SQLAlchemy that can interface with the database and lets us execute SQL queries in Python. But the basic idea of selecting data from database tables with conditions is relevant. + +### Databases with Heroku + +Heroku lets you "provision" your web app with a database, but it only supports PostgreSQL for Flask. + +To provision your app, follow the instructions at (Heroku guide) + +###### If you haven't got PostgreSQL installed properly yet +No worries: the Heroku database is on the Heroku servers, and the only reason for installing PostgreSQL locally (on your computer) is so that you can play with a local database. + +All Python installations come with SQLite, another database management system. You could play with that instead, but in the web application it's better to use the same database management system that Heroku's using or you'd run into messes when pushing to the Heroku servers. + +[commands to create a local SQLite database for demonstration purposes] + +###### If you do have PostgreSQL installed and working + +[commands to create a local PostgreSQL database for demonstration purposes] +```sql +psql +\d +\c +\l +\? +\q +select * from table_name; <-- need the semicolon! +``` + +## Connect to the database from a Flask web application + +Underneath `app = Flask(__name__)` in `app.py`, add the following: + +```python +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', + 'postgresql://localhost/techretreattemp') +db = SQLAlchemy(app) +``` + +This `configures` the `SQLALCHEMY_DATABASE_URI` variable by setting it to the `path` of your database. Aka it tells Flask where the database it should use is. +If `DATABASE_URL` isn't set, it'll fall back to the default. In the code above, this default is 'postgresql://localhost/techretreattemp' - the database stored locally on your computer. + +When you run the web app locally with `python app.py`, Flask uses the default local database. +When Heroku runs the web app, `DATABASE_URL` is set to the database that Heroku provides so Flask uses that one. + +## Storing comments + +Since we're using an `object-relational DBMS`, we work with objects. +First, define what a Comments object is by creating a `class`. + +We'll say a Comment has: +- + + + +In `app.py`: +import SQLAlchemy with + +```python +from flask.ext.sqlalchemy import SQLAlchemy +``` + +```python +class Comment(db.Model): + __tablename__ = 'comments' + + id = db.Column(db.Integer, primary_key=True) + poster = db.Column(db.String()) + comment = db.Column(db.String()) + + def __init__(self, poster, comment): + self.poster = poster + self.comment = comment + + def __repr__(self): + return '' .format(self.id) +``` + +### Database Migrations +Database migrations are changes to your database that are packaged and recorded down so that you can undo and redo database changes. [check this description...] + +We'll add a Python script that allows us to manage the migrations. [do they even know what a Python script is?] +```python +import os +from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_script import Manager +from flask_migrate import Migrate, MigrateCommand +from app import app, db + +app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', + 'postgresql://localhost/techretreattemp') + +migrate = Migrate(app, db) + +manager = Manager(app) +manager.add_command('db', MigrateCommand) + +class User(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(128)) + +if __name__ == '__main__': + manager.run() +``` + +We'll also add the file `migrations/env.py` [insert file] +What does all this code mean? +[description] +But in short, I got it from the official documentation example: https://flask-migrate.readthedocs.org/en/latest/ +Moral of the story: documentation is your best friend. Stack-Overflow is your second. + +##### .gitignore & More Command Line! + +Git tracks files, including a lot of automatically generated files that aren't supposed to be kept track of. To exclude those, your repository has an invisible `.gitignore` file. +You can edit it in the terminal/command line: + +> vim .gitignore + +- this will open up a primordial text editor inside your terminal/command line window +Here are the commands: (good luck) + + + +or you can just +> atom .gitignore + +to open it in Atom. (atom <3) +Make sure you navigated to the right directory in the terminal/command line [ / shell?? ] before you type these. To check where you are, you can use the command +> pwd + +We won't need all the files in the `venv` folder, since those are all the python requirements [libraries?] downloaded by running ` ` and Heroku will run that command itself to create its own `venv` folder. + +# Comments! + +This is the lifecycle of a comment: + +Alice types a comment + +This is the `form`: +________________ +name: + +comment: + + Submit +________________ + +She submits it. + +--> The request goes to our server +with all the information we specified: +- name +- comment + + Now we're going to save it permanently in our database. + +# Objects + +We're saving a comment. +In our words, a comment is: +a _string_ (the name) +and another _string_ (the comment) + + + +# __Model__, View, Controller + +Fields: +- id +- poster +- comment + +Mandatory methods: +__init__ + +__repr__ + +## HTTP Requests +We create a new `route` called `store_comment`. +The HTTP method for this is `POST`, because we're passing information. +To get this information, we can find it in +```py +request.form['poster'] # the poster +request.form['comment'] # the comment +``` +Now we create a `Comment`, passing the poster and comment which will call the special `__init__` method into action. +To add it to the database, we call +```py +db.session.add() +db.session.commit() # submits the comment to the database +``` +lmao I did this already + +### Security + +### Updating requirements.txt + +[Add gunicorn as well] + +### Remote migration + +## Showing comments + +To show the comments, we need to update the HTML in `templates/project/1` to show all the comments we have so far. +However, the HTML file doesn't have the comments. We can get all the comments using python in our route method in `app.py`, and then pass them to the HTML with the `render_template` method. + +```py +comments = Comment.query.all() +return render_template("/project/"+id+".html", comments=comments) +``` + +In the HTML file, we want to add all the comments. This needs a `for loop`. +HTML isn't a programming language - it just defines the structure and content of a website - but we can `embed` [programming ] in it using Flask's `templating engine`. + +```html +{% for comment in comments %} +
{{comment.poster}}
{{comment.comment}}
+{% endfor %} +``` + +## Make the like button work! +When a user __clicks__ the button # jQuery & javascript +make the number inside it go up by one # jQuery & javascript - DOM manipulation +When a user __hovers__ over the button # CSS +change the button image to the filled in button image # CSS + +## Add an about page to spruce up the website diff --git a/web/web_lesson_2.md b/web/web_lesson_2.md new file mode 100644 index 0000000..e69de29