Skip to content

Commit 768359d

Browse files
committed
docs: all tasks
1 parent 666fba5 commit 768359d

File tree

2 files changed

+121
-84
lines changed

2 files changed

+121
-84
lines changed

tasks.md

Lines changed: 119 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ You can preview your work by running `flask run` in the root of your fork and th
5050

5151
## 1.1 - Import Flask
5252

53-
@pytest.mark.app-import-flask In order to create a flask application Import `Flask` and `render_template` from `flask`.
53+
@pytest.mark.app-import-flask In order to create a flask application Import `Flask` and `render_template` from `flask` in `jobs/app.py`.
5454

5555
## 1.2 - Create a Flask Application
5656

57-
@pytest.mark.app-create-flask-app Create an instance of the Flask class called `app`. Pass in the special variable `__name__`.
57+
@pytest.mark.app-create-flask-app In `app.py` create an instance of the `Flask` class called `app`. Pass in the special variable `__name__` to the `Flask `constructor.
5858

5959
## 1.3 - Templates Folder
6060

@@ -66,15 +66,15 @@ You can preview your work by running `flask run` in the root of your fork and th
6666

6767
## 1.5 - Create the Index Route
6868

69-
@pytest.mark.app-create-index-route We will display all jobs on the index page. To start we will create a basic route that displays the contents of the index template. Create a function called `jobs` and attach a `route()` decorator with the URL of `/`. Add an additional path of `/jobs`. In the body of the function return a call to the `render_template()` passing the `index.html` template.
69+
@pytest.mark.app-create-index-route We will display all jobs on the index page. To start in `app.py` we will create a basic route that displays the contents of the index template. Create a function called `jobs` and attach a `route()` decorator with the URL of `/`. Add an additional path of `/jobs`. In the body of the function return a call to the `render_template()` passing in the `index.html` template.
7070

7171
## 1.5 - Create Employer and Job Templates
7272

7373
@pytest.mark.detail-templates In the root of the `templates` folder, create two files one called `employer.html` and the other called `job.html`.
7474

7575
## 1.6 -Create Detail Routes
7676

77-
@pytest.mark.app-create-detail-routes We need routes for individual employers and jobs. Create two functions one called `employer` and the other called `job`. Add route decorators to bind these functions with the appropriate URLs:
77+
@pytest.mark.app-create-detail-routes We need routes for individual employers and jobs. In `app.py` create two functions one called `employer` and the other called `job`. Add route decorators to bind these functions with the appropriate URLs:
7878
- `/employer` to the `employer` function
7979
- `/job` to the `job `function.
8080

@@ -88,7 +88,7 @@ In the body of each function return a call to `render_template()` passing the ap
8888

8989
## 2.2 - Add Styles
9090

91-
@pytest.mark.add-styles The app will be styled with bulma (bulma.io). Add three link tags to the head of `layout.html`. For the first `href` use mustache syntax `{{}}` and the `url_for()` function to link in the file `css/bulma.css` from the `static` folder. For the second add the file `css/app.css` using the same method. The last link tag should have an `href` value of `https://use.fontawesome.com/releases/v5.2.0/css/all.css`.
91+
@pytest.mark.add-styles The app will be styled with bulma (bulma.io). Add three link tags to the head of `layout.html`. For the first `href` use the mustache template markup `{{}}` and the `url_for()` function to link in the file `css/bulma.css` from the `static` folder. For the second add the file `css/app.css` using the same method. The last link tag should have an `href` value of `https://use.fontawesome.com/releases/v5.2.0/css/all.css`.
9292

9393
## 2.3 - Create Template Files
9494

@@ -117,148 +117,185 @@ Next create a new folder called `admin` in the `templates` folder, then create t
117117

118118
## 2.6 - Navigation
119119

120-
@pytest.mark.navigation We want to allow the user to navigate to the admin from the front page. In the `index.html` template file create a link to the main admin page by creating an `<a>` tag nested in the `<div>` with the two classes `columns` and `is-one-fifth`. The `<a>` tag should have an `href` with the value `/admin` and the classes `button`, `is-info`, and `is-pulled-right`. In the `admin/index.html` template file create a link to add a new job by creating an `<a>` tag nested in the `<div>` with the two classes `columns` and `is-one-fifth`. The `<a>` tag should have an `href` with the value `/admin` and the classes `button`, `is-info`, and `is-pulled-right`.
120+
@pytest.mark.navigation We want to allow the user to navigate to the admin from the front page. In the `index.html` template file create a link to the main admin page by creating an `<a>` tag nested in the `<div>` with the two classes `columns` and `is-one-fifth`. The `<a>` tag should have an `href` with the value `/admin` and the classes `button`, `is-info`, and `is-pulled-right`. In the admin we allow the user to create a new job. In the `admin/index.html` template file create a link to the new job form by creating an `<a>` tag nested in the `<div>` with the two classes `columns` and `is-one-fifth`. The `<a>` tag should have an `href` with the value `/admin/create` and the classes `button`, `is-info`, and `is-pulled-right`.
121121

122-
# Module 03 -
122+
# Module 03 - Database Access
123123

124-
## 3.1 -
124+
## 3.1 - Database Path
125125

126-
@pytest.mark.
126+
@pytest.mark.app-database-path In `app.py` and below the import statements create a constant called `DATABASE` that contains the path to the already created database stored in `db/jobs.sqlite`.
127127

128-
## 3.2 -
128+
## 3.2 - Import Global Namespace
129129

130-
@pytest.mark.
130+
@pytest.mark.app-import-global-namespace To provide access to the database through out the application we are going to create a function that stores a reference to the database connection in the application_context. Before we can do that in the `from flask` statement add `g` to the import.
131131

132-
## 3.3 -
132+
## 3.3 - Global Database Access
133133

134-
@pytest.mark.
134+
@pytest.mark.app-global-database-access At the top of `app.py` create a function called `get_db`. In the body of the function use the `getattr` function to get the `_database` attribute from the `g` object. If `_database` doesn't exist set the default to `None`. Assign the return value of the `getattr` function to`db`. Next test if `db` is `None` if it is set `db` to `g._database` and `sqlite3.connect(DATABASE)`. To make accessing data easier set the row_factory of `db` to sqlite3.row. This will set all rows to named tuples. Return the `db` variable.
135135

136-
## 3.4 -
136+
## 3.4 - Querying the Database
137137

138-
@pytest.mark.
138+
@pytest.mark.app-querying-the-database Lets create a function below the `get_db` function to make it easier to query the database. Call the function `query_db`, have the function accept three parameters: `query`, `args`, and `one`. Set the default of `args` to an empty tuple `()`. Set the default of `one` to `False`. Call the newly created `get_db` function and assign the return value to a `db` variable. Call the `execute` function, passing in the `query` and `args` variables, on the `db` and assign the return value to a variable called `cursor`. `fetchall()` data from the `cursor` and assign it to a variable called `results`. Close the `cursor` with the `close` function. Next test if there are `results` else return `None`. If there are results test if `one` is `True` and return `results[0]` else return `results`.
139139

140-
## 3.5 -
140+
## 3.5 - Close the Connection
141141

142-
@pytest.mark.
142+
@pytest.mark.app-close-the-connection In order to make sure the database connection is closed when the `app_context` is torn down create a function in `app.py` called `close_connection`. Add a parameter called `exception`. In the body of the function use the `getattr` function to get the `_database` attribute from the `g` object. If `_database` doesn't exist set the default to `None`. Assign the return value of the `getattr` function to`db`. If `db` is not `None` `close` the `db`. To ensure this function is called when the `app_context` is destroyed use the ``@app.teardown_appcontext` decorator.
143143

144-
## 3.6 -
144+
# Module 04 - Display Jobs and Employers
145145

146-
@pytest.mark.
146+
## 4.1 - All Jobs
147147

148-
## 3.7 -
148+
@pytest.mark.app-jobs In `app.py` locate the `jobs` function. Above the `render_template` function call, call the `query_db`function. Pass in the SQL statement: `'SELECT job.id, job.title, job.description, job.salary, employer.id as employer_id, employer.name as employer_name FROM job JOIN employer ON employer.id = job.employer_id'`. Assign the results of the call to a variable called `jobs`. In the `render_template` function, pass a keyword argument of `jobs=jobs`.
149149

150-
@pytest.mark.
150+
## 4.2 - Individual Job Details
151151

152-
## 3.8 -
152+
@pytest.mark.app-individual-job-details To bring back just one job from the database we are going to use a where clause. In the where clause we will need a `job_id`. We are going to get this from the URL. In `app.py` locate the `job` function. In the route decorator for the function after the url path `/job` add `/<job_id>`. To use this `job_id` we also need to pass it to the job function add `job_id` to the parameter list of the `job` function. Above the `render_template` function, call the `query_db` function and assign the results of the call to a `job` variable. Pass the function three arguments:
153+
- SQL Query: `'SELECT job.id, job.title, job.description, job.salary, employer.id as employer_id, employer.name as employer_name FROM job JOIN employer ON employer.id = job.employer_id WHERE job.id = ?'`
154+
- List Literal: [job_id]
155+
- True: This will bring back only one result.
153156

154-
@pytest.mark.
157+
In the `render_template` function, pass a keyword argument of `job=job`
155158

156-
## 3.9 -
159+
## 4.3 - Individual Employer Details
157160

158-
@pytest.mark.
161+
@pytest.mark.app-individual-employer-details Similar to the `job` function the employer route will only need the details of one employer. Locate the `employer` function in `app.py`. Again we need the unique id of an employer and will receive this from the URL. Add `/<employer_id>` in the route decorator after `/employer`. So that the `employer` function has access to this value add `employer_id`to the parameter list. Make a call to `query_db` and assign tne return value to `employer`. Pass in the arguments:
162+
- SQL Query: 'SELECT * FROM employer WHERE id=?'
163+
- List Literal: [employer_id]
164+
- True: This will bring back only one result.
159165

160-
## 3.10 -
166+
In the `render_template` function, pass a keyword argument of `employer=employer`
161167

162-
@pytest.mark.
168+
## 4.4 - All Employer Jobs
163169

164-
# Module 04 -
170+
@pytest.mark.app-all-employer-jobs On the employer details page we want to display all of the employers jobs. In the `employer` function in `app.py` below the `employer` variable, add a call to the `query_db` function and assign the results to a variable called `jobs`. Pass the function two arguments:
171+
- SQL Query: `'SELECT job.id, job.title, job.description, job.salary FROM job JOIN employer ON employer.id = job.employer_id WHERE employer.id = ?'`
172+
- List Literal: [employer_id]
165173

166-
## 4.1 -
174+
In the `render_template` function, add another keyword argument of `jobs=jobs`
167175

168-
@pytest.mark.
176+
## 4.5 - Job Card
169177

170-
## 4.2 -
178+
@pytest.mark.job-card Open the file `templates/_jobs.html` find the `<p>` tag with a class of `card-header-title`. Add an `<a>` tag with an `href` of `{{ url_for('job', job_id=job['id']) }}`. The content should be `{{ job['title'] }}`. Next find the `<div>` with a class of `content`. To this tag add a `<p>` tag and in this tag add the following:
179+
- `<a>` tag with an `href` of `{{ url_for('employer', employer_id=job['employer_id']) }}`. The content should be `{{ job['employer_name'] }}`. Add line break.
180+
- ${{ job['salary'] }}. Add line break.
181+
- {{ job['description'] }}
171182

172-
@pytest.mark.
183+
## 4.6 -Display All Jobs
173184

174-
## 4.3 -
185+
@pytest.mark.display-all-jobs Open the file `templates/index.html` above the `{% endblock %}` add a `<div>` with two classes `columns` and `is-multiline`. In the div add a `for in` loop that loops through all jobs. Use the `{% %}` template syntax, don't forget about ending the `for` loop.. In the `for` loop add a `<div>` with two classes `column` and `is-half`. Too this `<div>` add the following template code:
175186

176-
@pytest.mark.
177-
178-
## 4.4 -
179-
180-
@pytest.mark.
181-
182-
## 4.5 -
183-
184-
@pytest.mark.
187+
```
188+
{% with job=job %}
189+
{% include "_job.html" %}
190+
{% endwith %}
191+
```
185192

186-
## 4.6 -
193+
## 4.7 - Display Individual Job Details
187194

188-
@pytest.mark.
195+
@pytest.mark.display-individual-job-details In `templates/job.html` add a template block called `content` using the `{% %}` template markup. In the template block add the following template code:
189196

190-
## 4.7 -
197+
```
198+
{% with job=job %}
199+
{% include "_job.html" %}
200+
{% endwith %}
201+
```
191202

192-
@pytest.mark.
203+
## 4.8 - Display Individual Employer Details
193204

194-
## 4.8 -
205+
@pytest.mark.display-individual-employer-details Open `templates/employer.html` as the first thing in the template block add the following HTML:
195206

196-
@pytest.mark.
207+
- `<div>`
208+
- Nested in the `<div>` add an `<h1>` with the content {{ employer['name'] }}
209+
- Nested in the `<div>` add a`<div>` with a class of `description`
210+
- Nested in the description `<div>`add a`<p>` with the content {{ employer['description'] }}
211+
212+
## 4.9 -Display All Employer Jobs
197213

198-
## 4.9 -
214+
@pytest.mark.display-all-employer-jobs Open the file `templates/employer.html` below the jobs `<h2>` add a `<div>` with two classes `columns` and `is-multiline`. In the div add a `for in` loop that loops through all jobs. Use the `{% %}` template syntax, don't forget about ending the `for` loop.. In the `for` loop add a `<div>` with two classes `column` and `is-half`. To the `<div>` add the following template code:
199215

200-
@pytest.mark.
216+
```
217+
{% with job=job %}
218+
{% include "_job.html" %}
219+
{% endwith %}
201220
202-
## 4.10 -
221+
# Module 05 - Employer Reviews
203222
204-
@pytest.mark.
223+
## 5.1 - Review Route
205224
206-
## 5.1 -
225+
@pytest.mark.app-review-route In `app.py` below the `employer` function create a new function called review. Add `employer_id` to the parameter list. Add a route decorator will a URL pattern of `/employer/<employer_id>/review` as well as a keyword argument `methods` set to a tuple with two values: 'GET' and 'POST'.
226+
In the body of the function return the render_template function passing in `review.html` template and a keyword argument of `employer_id=employer_id`.
207227
208-
@pytest.mark.
228+
## 5.2 - Check for POST method
209229
210-
## 5.2 -
230+
@pytest.mark.app-review-check-for-post-method In the body of the `review` above the render_template function call, create an `if` statement that checks if the request method is 'POST'. In the `if` statement create four variables `review`, `rating`, `title`, and `status`. Set them equal to their respective `request.form` values i.e. `request.form['review']`. Create two more variables `error` (set to `None`) and `date` (set to `datetime.datetime.now().strftime("%m/%d/%Y")`) . For `datetime` add an `import datetime` statement to the top of `app.py`.
211231
212-
@pytest.mark.
232+
## 5.3 - Check for Values
213233
214-
## 5.3 -
234+
@pytest.mark.app-review-check-for-values In the body of the post `if` statement in the review function in `app.py`, below the variables check if there is a value for `review`, `rating`, and `title`. If any of these are empty set `error` to an appropriate error message i.e. 'Review field is required.'
215235
216-
@pytest.mark.
236+
## 5.4 - Check for Error
217237
218-
## 5.4 -
238+
@pytest.mark.app-review-check-for-error Still in the review function below the value checks add an `if` statement that checks if `error` is `None`. If there are no errors we are going to add the form values to the database. To do this we need to connect to the database and commit some changes. Follow these steps:
239+
- Set a `db` variable to a call to `get_db()`
240+
- `execute` the following SQL statment: `'INSERT INTO review (review, rating, title, date, status, employer_id) VALUES (?, ?, ?, ?, ?, ?)'` passing the values: `(review, rating, title, date, status, employer_id)`
241+
- `commit` the changes to the database.
242+
- return a redirect taking the user back to the employer page. **Hint: use `redirect()` and `url_for()` (pass keyword argument of `employer_id=employer_id`) both of which need to be imported from flask.**
219243
220-
@pytest.mark.
244+
If there are errors (`else` statement) `flash` the error. **Hint: `else` statement; use `flash()` (imported from flask)**
221245
222-
## 5.5 -
246+
## 5.5 - Review Form Cancel
223247
224-
@pytest.mark.
248+
@pytest.mark.review-form-cancel Open `templates/review.html` and find the cancel anchor tag. Add an `href` attribute with a value of ``{{ url_for('employer', employer_id=employer_id) }}`.
225249
226-
## 5.6 -
250+
## 5.6 - Individual Employer Reviews
227251
228-
@pytest.mark.
252+
@pytest.mark.app-individual-employer-reviews Now that employer reviews can be created, lets display them on the individual employer pages. Switch back to `app.py` and find the `employer` function below the jobs query add an new query to get all review for the employer. Make a call to `query_db` and assign tne return value to `reviews`. Pass in the arguments:
253+
- SQL Query: 'SELECT review, rating, title, date, status FROM review JOIN employer ON employer.id = review.employer_id WHERE employer.id = ?'
254+
- List Literal: [employer_id]
229255
230-
## 5.7 -
256+
In the `render_template` function, add another keyword argument of `reviews=reviews`
231257
232-
@pytest.mark.
258+
## 5.7 - Display Individual Employer Reviews
233259
234-
## 5.8 -
260+
@pytest.mark.display-individual-employer-reviews Open `templates/employer.html` find the review `<h2>` in the empty `{% %}` template tag add a `for in` loop to loop through all `reviews`. Add the `endfor` directive to the second empty `{% %}` template tag. In the `<div>` with a class of `media-left` add this for loop:
261+
```
262+
{% for _ in range(1, review['rating']): %}
263+
<span class="fa fa-star checked"></span>
264+
{% endfor %}
265+
```
266+
In the `content <div>` add a paragraph tag. In the paragraph display the details of a review:
267+
- `title`
268+
- `status`
269+
- `date`
270+
- `review`
235271
236-
@pytest.mark.
272+
For the `Create Review` button to work add an `href` that points to the individual employer page.
237273
238-
## 5.9 -
274+
# Module 06 - Add Jobs
239275
240-
@pytest.mark.
276+
## 6.1 - Admin Route
241277
242-
## 5.10 -
278+
@pytest.mark.app-admin-route We will display all jobs on the admin page. To start, in `app.py` create a basic route that displays the contents of the admin index template. Create a function called `admin` and attach a `route()` decorator with the URL of `/admin`. In the body of the function use the `query_db` function to get all jobs from the database. The SQL can be found in other routes. Next, return a call to the `render_template()` passing in the `admin/index.html` template and the correct keyword arguments.
243279
244-
@pytest.mark.
280+
## 6.2 - Admin Create Job Route
245281
246-
## 5.11 -
282+
@pytest.mark.app-admin-create-job-route In `app.py` create a route at the path `/admin/create` that accepts the methods 'GET' and 'POST'.
247283
248-
@pytest.mark.
284+
## 6.3 - Check for POST method
249285
250-
## 5.12 -
286+
@pytest.mark.app-admin-check-for-post-method In the body of your route check if data has been posted then create four variables `title`, `description`, `salary`, and `employer_id`. Set them equal to their respective `request.form` values. Create an `error` variable set to `None`.
251287
252-
@pytest.mark.
288+
## 6.3 - Check for Values
253289
254-
## 5.13 -
290+
@pytest.mark.app-admin-check-for-values In the body of the post `if` statement in your route function in `app.py`, below the variables, check if there is a value for `title`, and `employer_id`. If either is empty set `error` to an appropriate error message i.e. 'Title field is required.'
255291
256-
@pytest.mark.
292+
## 6.4 - Check for Error
257293
258-
## 5.14 -
294+
@pytest.mark.app-admin-check-for-error Still in your route function below the value checks add an `if` statement that checks if `error` is `None`. If there are no errors we are going to add the form values to the database. Connect to the database and commit the changes.
295+
**Hint: The SQL is `'INSERT INTO job (title, description, salary, employer_id) VALUES (?, ?, ?, ?)'`**
259296
260-
@pytest.mark.
297+
If there are errors `flash` the error. **Hint: `else` statement**
261298
262-
## 5.15 -
299+
## 6.5 - Admin Navigation
263300
264-
@pytest.mark.
301+
@pytest.mark.admin-navigation Find the admin index template and add an href attribute to the `New Job` link. Send the user to the URL ``/admin/create`. Open create job template and find the cancel anchor tag. Point the link back to the admin page using `url_for()`.

0 commit comments

Comments
 (0)