Commit 5f41bf8b authored by Давид Ли's avatar Давид Ли

completed 39 lesson

parent 38ccb863
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.11 (http_framework)" jdkType="Python SDK" /> <orderEntry type="jdk" jdkName="Python 3.11 (http_framework)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="bootstrap" level="application" />
</component> </component>
</module> </module>
\ No newline at end of file
from request import Request from src.request import Request
from response import Response from src.response import Response
class BaseController: class BaseController:
......
from .base import BaseController from controllers.base import BaseController
class PagesController(BaseController): class PagesController(BaseController):
......
import utils
from controllers.base import BaseController from controllers.base import BaseController
from db.database import Database
from template_engine.jinja import env
def id_generator(): from utils import id_gen
count = 0
while True:
count += 1
yield count
id_gen = id_generator()
class PostsController(BaseController): class PostsController(BaseController):
posts_db = [
{'id': next(id_gen), 'title': 'This is 1 post'},
{'id': next(id_gen), 'title': 'This is 2 post'},
{'id': next(id_gen), 'title': 'This is 3 post'},
]
def get_list(self): def get_list(self):
body = ( tmp = env.get_template('posts/list.html')
'<h1>This is posts page</h1>' body = tmp.render(posts=Database.all())
'<br><form action="/posts" method="POST">'
'<label>' self.response.add_header('Content-Type', 'text/html')
'<input type="text" name="title">' self.response.set_body(body)
'</label>'
'<input type="submit">'
'</form><br>'
)
for post in self.posts_db: def new(self):
body += f'<h3>{post["id"]} - {post["title"]}' tmp = env.get_template('posts/create.html')
body = tmp.render(id=next(utils.id_gen))
self.response.add_header('Content-Type', 'text/html') self.response.add_header('Content-Type', 'text/html')
self.response.set_body(body) self.response.set_body(body)
def create(self): def create(self):
id_ = next(id_gen) id_ = next(id_gen)
self.posts_db.append( Database.add(
{ {
'id': id_, 'id': id_,
'title': f'This is {id_} post' 'title': self.request.body['title']
} }
) )
self.response.add_header('Content-Type', 'text/html') self.response.add_header('Content-Type', 'text/html')
self.response.set_status(301)
self.response.add_header('Location', '/posts')
self.response.set_body('<a href="/posts"">Back to posts list</a>') self.response.set_body('<a href="/posts"">Back to posts list</a>')
from utils import id_gen
class Database:
posts = [
{'id': next(id_gen), 'title': 'This is 1 post'},
{'id': next(id_gen), 'title': 'This is 2 post'},
{'id': next(id_gen), 'title': 'This is 3 post'},
]
@classmethod
def all(cls):
return cls.posts
@classmethod
def add(cls, post: dict[str]):
cls.posts.append(post)
from controllers.pages import PagesController
from controllers.posts import PostsController
from src.router import Router
from src.server import runserver
config = {
'host': 'localhost',
'port': 1025,
'static': 'static'
}
router = Router()
router.get('/', PagesController, 'home')
router.get('/about-us', PagesController, 'about_us')
router.get('/posts', PostsController, 'get_list')
router.post('/posts', PostsController, 'create')
router.get('/posts/new', PostsController, 'new')
runserver(router, config)
Jinja2==3.1.2
MarkupSafe==2.1.2
import socketserver
from controllers.pages import PagesController
from controllers.posts import PostsController
from request import Request
from response import Response
from router import Router
from static_responder import StaticResponder
import errors
HOST, PORT = '127.0.0.1', 1025
# CRUDL - Create, Read, Update, Delete, List
# /posts
# GET - /posts
# GET - /posts/{id}
# POST - /posts
# PUT/PATCH - /posts/{id}
# DELETE - /posts/{id}
router = Router()
router.get('/', PagesController, 'home')
router.get('/about-us', PagesController, 'about_us')
router.get('/posts', PostsController, 'get_list')
router.post('/posts', PostsController, 'create')
class MyTCPHandler(socketserver.StreamRequestHandler):
def handle(self) -> None:
request = Request(file=self.rfile)
response = Response(file=self.wfile)
static_responder = StaticResponder(request, response, 'static')
router.run(request, response)
print(
f'Method: {request.method}\n'
f'URI: {request.uri}\n'
f'Protocol: {request.protocol}\n'
)
response.send()
socketserver.TCPServer.allow_reuse_address = True
with socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever()
from request import Request from src.request import Request
from response import Response from src.response import Response
def not_found(request: Request, response: Response): def not_found(request: Request, response: Response):
......
...@@ -45,4 +45,4 @@ class Request: ...@@ -45,4 +45,4 @@ class Request:
self.body = parsed self.body = parsed
else: else:
self.body = self.file.read(content_length) self.body = body
...@@ -8,12 +8,14 @@ class Response: ...@@ -8,12 +8,14 @@ class Response:
HTTP_BAD_REQUEST = 400 HTTP_BAD_REQUEST = 400
HTTP_NOT_FOUND = 404 HTTP_NOT_FOUND = 404
HTTP_INTERNAL_SERVER_ERROR = 500 HTTP_INTERNAL_SERVER_ERROR = 500
HTTP_MOVED_PERMANENTLY = 301
MESSAGES = { MESSAGES = {
HTTP_OK: 'OK', HTTP_OK: 'OK',
HTTP_BAD_REQUEST: 'Bad Request', HTTP_BAD_REQUEST: 'Bad Request',
HTTP_NOT_FOUND: 'Not Found', HTTP_NOT_FOUND: 'Not Found',
HTTP_INTERNAL_SERVER_ERROR: 'Internal Server Error' HTTP_INTERNAL_SERVER_ERROR: 'Internal Server Error',
HTTP_MOVED_PERMANENTLY: 'Moved Permanently'
} }
PROTOCOL = 'HTTP/1.1' PROTOCOL = 'HTTP/1.1'
...@@ -30,7 +32,7 @@ class Response: ...@@ -30,7 +32,7 @@ class Response:
def set_body(self, body: str) -> None: def set_body(self, body: str) -> None:
self.body = body.encode() self.body = body.encode()
self.add_header('Content-Type', str(len(self.body))) self.add_header('Content-Length', str(len(self.body)))
def set_file_body(self, file: BinaryIO) -> None: def set_file_body(self, file: BinaryIO) -> None:
self.file_body = file self.file_body = file
...@@ -41,7 +43,11 @@ class Response: ...@@ -41,7 +43,11 @@ class Response:
self.__headers.append({name: value}) self.__headers.append({name: value})
def __get_status_line(self) -> str: def __get_status_line(self) -> str:
if self.__status in self.MESSAGES:
message = self.MESSAGES[self.__status] message = self.MESSAGES[self.__status]
else:
message = ''
return f'{self.PROTOCOL} {self.__status} {message}' return f'{self.PROTOCOL} {self.__status} {message}'
def __get_response_head(self) -> bytes: def __get_response_head(self) -> bytes:
......
import errors from src import errors
from controllers.base import BaseController from controllers.base import BaseController
from request import Request from src.request import Request
from response import Response from src.response import Response
class Router: class Router:
......
import socketserver
from src.request import Request
from src.response import Response
from src.router import Router
from src.static_responder import StaticResponder
def runserver(router: Router, config: dict[str]) -> None:
class MyTCPHandler(socketserver.StreamRequestHandler):
def handle(self) -> None:
request = Request(file=self.rfile)
response = Response(file=self.wfile)
static_responder = StaticResponder(request, response, config['static'])
if static_responder.file:
static_responder.prepare_response()
else:
router.run(request, response)
print(
f'Method: {request.method}\n'
f'URI: {request.uri}\n'
f'Protocol: {request.protocol}\n'
)
response.send()
socketserver.TCPServer.allow_reuse_address = True
with socketserver.ThreadingTCPServer((config['host'], config['port']), MyTCPHandler) as server:
server.serve_forever()
...@@ -2,8 +2,8 @@ from glob import glob ...@@ -2,8 +2,8 @@ from glob import glob
import os import os
from request import Request from src.request import Request
from response import Response from src.response import Response
class StaticResponder: class StaticResponder:
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="../static/styles.css"> <link rel="stylesheet" href="../../static/styles.css">
<title>Title</title> <title>Title</title>
</head> </head>
<body> <body>
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.1/css/bootstrap.min.css"
integrity="sha512-Ez0cGzNzHR1tYAv56860NLspgUGuQw16GiOOp/I2LuTmpSK9xDXlgJz3XN4cnpXWDmkNBKXR/VDMTCnAaEooxA=="
crossorigin="anonymous" referrerpolicy="no-referrer"/>
<link rel="stylesheet" href="styles.css">
<title>Title</title>
</head>
<body>
<div class="container container-2">
{% block content %}
{% endblock %}
</div>
</body>
</html>
\ No newline at end of file
{% extends 'posts/base.html' %}
{% block content %}
<form action="/posts" method="post">
<div class="mb-3 row">
<label for="staticEmail" class="col-sm-2 col-form-label">Id</label>
<div class="col-sm-10">
<input type="text" readonly class="form-control-plaintext" id="staticEmail" value="{{ id }}">
</div>
</div>
<div class="mb-3 row">
<label for="inputPassword" class="col-sm-2 col-form-label">Title</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="inputPassword" name="title">
</div>
</div>
<button class="btn btn-success">Submit</button>
</form>
{% endblock %}
\ No newline at end of file
{% extends 'posts/base.html' %}
{% block content %}
<h1>This is the posts page</h1>
<div class="row">
{% for post in posts %}
<div class="col-4">
<div class="card">
<div class="card-header">
{{ post.id }}
</div>
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<p class="card-text">With supporting text below as a natural lead-in to additional content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
\ No newline at end of file
...@@ -6,7 +6,6 @@ h1 { ...@@ -6,7 +6,6 @@ h1 {
color: red color: red
} }
.container { .container-2 {
margin: 0 auto; background-color: red;
width: 80%;
} }
from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
loader=PackageLoader('src'),
autoescape=select_autoescape()
)
def id_generator():
count = 0
while True:
count += 1
yield count
id_gen = id_generator()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment