From 149180683dcd8d15adb8b760363bb1e4db9c57e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Sun, 1 Apr 2018 00:12:40 +0300 Subject: [PATCH] Start writing html generation --- generate_html.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ server.py | 35 +++++++++++++---- 2 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 generate_html.py diff --git a/generate_html.py b/generate_html.py new file mode 100644 index 0000000..7d14364 --- /dev/null +++ b/generate_html.py @@ -0,0 +1,97 @@ +import urllib.parse + +import bs4 + +# generate_nav(*, soup) → nav_tag +def generate_nav(*, soup): + # TODO: Don't generate link to a board if we're at the index + nav_tag = soup.new_tag('nav') + + for board in ['a', 'b', 'his', 'g']: + url = '/' + urllib.parse.quote(board, safe = '') + '/' + a_tag = soup.new_tag('a', href = url) + a_tag.string = '/' + board + '/' + nav_tag.append(a_tag) + + return nav_tag + +# generate_header(*, page_title, soup) → header_tag +def generate_header(*, page_title, soup): + header_tag = soup.new_tag('header') + + h1_tag = soup.new_tag('h1') + h1_tag.string = page_title + header_tag.append(h1_tag) + + return header_tag + +# generate_footer(*, soup) → footer_tag +def generate_footer(*, soup): + # TODO: Add footer generation + return soup.new_tag('footer') + +# page_skeleton(*, page_title, contents, soup) → html +# Given page title (string) and contents (iteratable of beautifulsoup tags), create the html +# Since most pages have same basic structure, it makes sense to factor this out from page creation functions +def page_skeleton(*, page_title, contents, soup): + # Doctype and head are more or less the same for each page, no need to do anything fancy when adding them + soup.append(bs4.Doctype('html')) + + head_tag = soup.new_tag('head') + title_tag = soup.new_tag('title') + title_tag.string = page_title + head_tag.append(title_tag) + soup.append(head_tag) + + # Body consists of (more or less same) header and footer, and varying content + body_tag = soup.new_tag('body') + + body_tag.append(generate_nav(soup = soup)) + body_tag.append(generate_header(page_title = page_title, soup = soup)) + + # contents is an iterable that can contain several tags + for tag in contents: + body_tag.append(tag) + + body_tag.append(generate_footer(soup = soup)) + + soup.append(body_tag) + + # Use .prettify() to generate nice-looking HTML + # We are probably never going to serve enough pages for the additional whitespace to count for data usage + return soup.prettify() + +# new_soup() → soup +# Since we need a soup object to create tags, split this from page_skeleton +def new_soup(): + # Use python's built-in parser for portability + # We'll be constructing the document programmatically, so start with empty tree + soup = bs4.BeautifulSoup('', 'html.parser') + + return soup + +# board() → html +# Creates the board index page +def board(board_name): + # TODO: Creae a board index page + soup = new_soup() + + page_title = '/' + board_name + '/' + + return page_skeleton(page_title = page_title, contents = [], soup = soup) + +# index() → html +# Create the site index +def index(): + # TODO: Create an index page + soup = new_soup() + return page_skeleton(page_title = 'Buranun', contents = [], soup = soup) + +# error_404(path) → html +def error_404(path): + soup = new_soup() + + p_tag = soup.new_tag('p') + p_tag.string = path + ' does not exist' + + return page_skeleton(page_title = '404 Not Found', contents = [p_tag], soup = soup) diff --git a/server.py b/server.py index a7dc25f..56d90a2 100644 --- a/server.py +++ b/server.py @@ -1,27 +1,46 @@ import http.server import urllib.parse +import generate_html + class HTTPRequestHandler(http.server.BaseHTTPRequestHandler): server_version = 'Buranun/0.0' protocol_version = 'HTTP/1.1' - def __send_plaintext(self, string): - if string[-1:] != '\n': - string += '\n' - - encoded = string.encode('utf-8') + def __send_html(self, html, *, status_code = 200): + encoded = html.encode('utf-8') length = len(encoded) - self.send_response(200) - self.send_header('Content-Type', 'text/plain; charset=utf-8') + self.send_response(status_code) + self.send_header('Content-Type', 'text/html; charset=utf-8') self.send_header('Content-Length', length) self.end_headers() self.wfile.write(encoded) + def __send_404(self, path): + html = generate_html.error_404(path) + self.__send_html(html, status_code = 404) + def do_GET(self): path = urllib.parse.unquote(self.path) - self.__send_plaintext(path) + + path_components = [component for component in path.split('/') if component != ''] + + if len(path_components) == 0: + # Path of format / → index + html = generate_html.index() + self.__send_html(html) + + elif len(path_components) == 1: + # Path of format /foo/ → board index + board_name = path_components[0] + html = generate_html.board(board_name) + self.__send_html(html) + + else: + # Path not understood, send 404 + self.__send_404(path) def main(): httpd = http.server.HTTPServer(('', 8000), HTTPRequestHandler)