Skip to content

Commit 3e4c8a4

Browse files
committed
Initialize chapter 6
1 parent 9a2ad2c commit 3e4c8a4

File tree

11 files changed

+420
-0
lines changed

11 files changed

+420
-0
lines changed

ch06/planner/database/__init__.py

Whitespace-only changes.

ch06/planner/main.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from fastapi import FastAPI
2+
from fastapi.responses import RedirectResponse
3+
4+
from routes.users import user_router
5+
from routes.events import event_router
6+
7+
import uvicorn
8+
9+
app = FastAPI()
10+
11+
# Register routes
12+
13+
app.include_router(user_router, prefix="/user")
14+
app.include_router(event_router, prefix="/event")
15+
16+
17+
@app.get("/")
18+
async def home():
19+
return RedirectResponse(url="/event/")
20+
21+
if __name__ == '__main__':
22+
uvicorn.run("main:app", host="0.0.0.0", port=8080, reload=True)

ch06/planner/models/__init__.py

Whitespace-only changes.

ch06/planner/models/events.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import List
2+
3+
from pydantic import BaseModel
4+
5+
6+
class Event(BaseModel):
7+
id: int
8+
title: str
9+
image: str
10+
description: str
11+
tags: List[str]
12+
location: str
13+
14+
class Config:
15+
schema_extra = {
16+
"example": {
17+
"title": "FastAPI BookLaunch",
18+
"image": "https://linktomyimage.com/image.png",
19+
"description": "We will be discussing the contents of the FastAPI book in this event.Ensure to come with your own copy to win gifts!",
20+
"tags": ["python", "fastapi", "book", "launch"],
21+
"location": "Google Meet"
22+
}
23+
}

ch06/planner/models/users.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from typing import Optional, List
2+
3+
from fastapi import Form
4+
from pydantic import BaseModel, EmailStr
5+
6+
from models.events import Event
7+
8+
9+
class User(BaseModel):
10+
email: EmailStr
11+
username: str
12+
events: Optional[List[Event]]
13+
14+
@classmethod
15+
def as_form(
16+
cls,
17+
email: EmailStr = Form(...),
18+
username: str = Form(...),
19+
password: str = Form(...)
20+
):
21+
return cls(email=email, username=username, password=password)
22+
23+
class Config:
24+
schema_extra = {
25+
"example": {
26+
"email": "fastapi@packt.com",
27+
"username": "fastapipackt001",
28+
"events": [],
29+
}
30+
}
31+
32+
33+
class NewUser(User):
34+
password: str
35+
36+
class Config:
37+
schema_extra = {
38+
"example": {
39+
"email": "fastapi@packt.com",
40+
"password": "Stro0ng!",
41+
"username": "FastPackt"
42+
}
43+
}
44+
45+
46+
class UserSignIn(BaseModel):
47+
email: EmailStr
48+
password: str
49+
50+
@classmethod
51+
def as_form(
52+
cls,
53+
email: EmailStr = Form(...),
54+
password: str = Form(...)
55+
):
56+
return cls(email=email, password=password)
57+
58+

ch06/planner/routes/__init__.py

Whitespace-only changes.

ch06/planner/routes/events.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from fastapi import APIRouter, Body, HTTPException, Request, status
2+
from fastapi.responses import HTMLResponse
3+
from fastapi.templating import Jinja2Templates
4+
5+
from models.events import Event
6+
from typing import List
7+
8+
event_router = APIRouter(
9+
tags=["Events"]
10+
)
11+
12+
templates = Jinja2Templates(directory="templates/")
13+
14+
events = []
15+
16+
17+
@event_router.get("/", response_class=HTMLResponse)
18+
async def retrieve_all_events(request: Request):
19+
return templates.TemplateResponse(
20+
"event.html",
21+
{
22+
"request": request,
23+
"events": events
24+
}
25+
)
26+
27+
28+
@event_router.get("/{id}", response_class=HTMLResponse)
29+
async def retrieve_event(id: int, request: Request):
30+
for event in events:
31+
if event.id == id:
32+
return templates.TemplateResponse(
33+
"event.html",
34+
{
35+
"request": request,
36+
"event": event
37+
}
38+
)
39+
40+
raise HTTPException(
41+
status_code=status.HTTP_404_NOT_FOUND,
42+
detail="Event with supplied ID does not exist"
43+
)
44+
45+
46+
@event_router.post("/new")
47+
async def create_event(body: Event = Body(...)):
48+
events.append(body)
49+
return {
50+
"message": "Event created successfully"
51+
}
52+
53+
54+
@event_router.delete("/{id}")
55+
async def delete_event(id: int):
56+
for event in events:
57+
if event.id == id:
58+
events.remove(event)
59+
return {
60+
"message": "Event deleted successfully"
61+
}
62+
63+
raise HTTPException(
64+
status_code=status.HTTP_404_NOT_FOUND,
65+
detail="Event with supplied ID does not exist"
66+
)

ch06/planner/routes/users.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from fastapi import APIRouter, HTTPException, Request, status, Depends
2+
from fastapi.templating import Jinja2Templates
3+
4+
from models.users import NewUser, UserSignIn
5+
6+
user_router = APIRouter(
7+
tags=["User"],
8+
)
9+
10+
users = {}
11+
templates = Jinja2Templates(directory="templates/")
12+
13+
14+
@user_router.post("/signup")
15+
async def sign_user_up(request: Request, data: NewUser = Depends(NewUser.as_form)):
16+
if data.email in users:
17+
raise HTTPException(
18+
status_code=status.HTTP_409_CONFLICT,
19+
detail="User with supplied username exists"
20+
)
21+
22+
users[data.email] = data
23+
24+
return templates.TemplateResponse("user.html", {
25+
"request": request,
26+
"signed_in": True,
27+
})
28+
29+
30+
@user_router.post("/signin")
31+
async def sign_user_in(request: Request, user: UserSignIn = Depends(UserSignIn.as_form)):
32+
if user.email not in users:
33+
raise HTTPException(
34+
status_code=status.HTTP_404_NOT_FOUND,
35+
detail="User does not exist"
36+
)
37+
38+
if users[user.email].password != user.password:
39+
raise HTTPException(
40+
status_code=status.HTTP_403_FORBIDDEN,
41+
detail="Wrong credential passed"
42+
)
43+
return templates.TemplateResponse(
44+
"index.html",
45+
{
46+
"request": request,
47+
"signed_in": True
48+
}
49+
)
50+
51+
52+
@user_router.get("/")
53+
async def render_login_page(request: Request):
54+
return templates.TemplateResponse(
55+
"user.html", {
56+
"request": request,
57+
"sign_in": True
58+
}
59+
)
60+
61+
62+
@user_router.get("/signup")
63+
async def render_signup_page(request: Request):
64+
return templates.TemplateResponse(
65+
"user.html", {
66+
"request": request,
67+
"sign_in": False
68+
}
69+
)

ch06/planner/templates/event.html

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{% extends "index.html" %}
2+
3+
{% block events %}
4+
5+
{% if event %}
6+
<section class="post-content-section">
7+
<div class="container">
8+
<div class="thumbnail">
9+
<img src="{{ event.image }}" alt="{{ event.title }}">
10+
<div class="caption">
11+
<h2>{{ event.title }}</h2>
12+
</div>
13+
</div>
14+
<p>
15+
{{ event.description }}
16+
</p>
17+
18+
<h4>Location</h4>
19+
<p>{{ event.location }}</p>
20+
21+
<h4>Tags</h4>
22+
<p>{{ event.tags | join(', ') | capitalize }}</p>
23+
</div>
24+
25+
</section>
26+
{% endif %}
27+
28+
{% for event in events %}
29+
<div class="jumbotron card">
30+
<div class="container-fluid">
31+
<div class="thumbnail">
32+
<img src="{{ event.image }}" class="img-fluid" alt="{{ event.title }}">
33+
<div class="caption">
34+
<h2><a href="/event/{{ event.id }}"> {{ event.title }} </a></h2>
35+
</div>
36+
</div>
37+
<h4>Description</h4>
38+
<p>{{ event.description }} </p>
39+
40+
<h4>Location</h4>
41+
<p>This event will be happening in {{ event.location }}</p>
42+
43+
<h4>Tags</h4>
44+
{{ event.tags | join(', ') | capitalize }}
45+
</div>
46+
</div>
47+
48+
{% endfor %}
49+
50+
{% endblock %}

ch06/planner/templates/index.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Packt Event Planner</title>
8+
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
9+
integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
10+
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.10/css/all.css"
11+
integrity="sha384-+d0P83n9kaQMCwj8F4RJB66tzIwOKmrdb46+porD/OvrJ+37WqIM7UoBtwHO6Nlg" crossorigin="anonymous">
12+
</head>
13+
<body>
14+
<header>
15+
<nav class="navbar navbar-default navbar-static-top">
16+
<div class="container-fluid">
17+
<div style="text-align: center;" class="navbar-header">
18+
<h1>Packt Event Planner</h1>
19+
</div>
20+
<ul class="nav navbar-nav navbar-right">
21+
{% if signed_in %}
22+
<button type="button" class="btn btn-primary navbar-btn">Sign Out</button>
23+
{% else %}
24+
<a href="/user/" class="btn btn-primary" role="button">Sign In</a>
25+
{% endif %}
26+
</ul>
27+
</div>
28+
</nav>
29+
</header>
30+
<div class="container-fluid">
31+
Welcome to Packt's event planner! Check out the events happening around the globe.
32+
<hr>
33+
{% block user %}{% endblock %}
34+
{% block events %}{% endblock %}
35+
36+
37+
</div>
38+
</body>
39+
</html>

0 commit comments

Comments
 (0)