X-Git-Url: https://plomlompom.com/repos/template?a=blobdiff_plain;f=plomtask%2Fhttp.py;h=55473ea85410f840a6bbfe32e41ba245b1a85202;hb=014e59d97c912cff4ae2922c1d9284c086694cf1;hp=fc0059c530e20c5e347a264703905b3fcadcb3df;hpb=c5449a0b00f8865b1129ed56bdd16f1cc055bc87;p=plomtask diff --git a/plomtask/http.py b/plomtask/http.py index fc0059c..55473ea 100644 --- a/plomtask/http.py +++ b/plomtask/http.py @@ -6,6 +6,7 @@ from base64 import b64encode, b64decode from http.server import BaseHTTPRequestHandler from http.server import HTTPServer from urllib.parse import urlparse, parse_qs +from json import dumps as json_dumps from os.path import split as path_split from jinja2 import Environment as JinjaEnv, FileSystemLoader as JinjaFSLoader from plomtask.dating import date_in_n_days @@ -16,6 +17,7 @@ from plomtask.db import DatabaseConnection, DatabaseFile from plomtask.processes import Process, ProcessStep, ProcessStepsNode from plomtask.conditions import Condition from plomtask.todos import Todo +from plomtask.db import BaseModel TEMPLATES_DIR = 'templates' @@ -27,7 +29,37 @@ class TaskServer(HTTPServer): *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.db = db_file - self.jinja = JinjaEnv(loader=JinjaFSLoader(TEMPLATES_DIR)) + self.headers: list[tuple[str, str]] = [] + self._render_mode = 'html' + self._jinja = JinjaEnv(loader=JinjaFSLoader(TEMPLATES_DIR)) + + def set_json_mode(self) -> None: + """Make server send JSON instead of HTML responses.""" + self._render_mode = 'json' + self.headers += [('Content-Type', 'application/json')] + + @staticmethod + def ctx_to_json(ctx: dict[str, object]) -> str: + """Render ctx into JSON string.""" + def walk_ctx(node: object) -> Any: + if isinstance(node, BaseModel): + return node.as_dict + if isinstance(node, (list, tuple)): + return [walk_ctx(x) for x in node] + if isinstance(node, HandledException): + return str(node) + return node + for k, v in ctx.items(): + ctx[k] = walk_ctx(v) + return json_dumps(ctx) + + def render(self, ctx: dict[str, object], tmpl_name: str = '') -> str: + """Render ctx according to self._render_mode..""" + tmpl_name = f'{tmpl_name}.{self._render_mode}' + if 'html' == self._render_mode: + template = self._jinja.get_template(tmpl_name) + return template.render(ctx) + return self.__class__.ctx_to_json(ctx) class InputsParser: @@ -106,11 +138,18 @@ class TaskHandler(BaseHTTPRequestHandler): _form_data: InputsParser _params: InputsParser - def _send_html(self, html: str, code: int = 200) -> None: + def _send_page(self, + ctx: dict[str, Any], + tmpl_name: str, + code: int = 200 + ) -> None: """Send HTML as proper HTTP response.""" + body = self.server.render(ctx, tmpl_name) self.send_response(code) + for header_tuple in self.server.headers: + self.send_header(*header_tuple) self.end_headers() - self.wfile.write(bytes(html, 'utf-8')) + self.wfile.write(bytes(body, 'utf-8')) @staticmethod def _request_wrapper(http_method: str, not_found_msg: str @@ -142,9 +181,8 @@ class TaskHandler(BaseHTTPRequestHandler): for cls in (Day, Todo, Condition, Process, ProcessStep): assert hasattr(cls, 'empty_cache') cls.empty_cache() - tmpl = self.server.jinja.get_template('msg.html') - html = tmpl.render(msg=error) - self._send_html(html, error.http_code) + ctx = {'msg': error} + self._send_page(ctx, 'msg', error.http_code) finally: self.conn.close() return wrapper @@ -154,13 +192,11 @@ class TaskHandler(BaseHTTPRequestHandler): def do_GET(self, handler: Callable[[], str | dict[str, object]] ) -> str | None: """Render page with result of handler, or redirect if result is str.""" - template = f'{self._site}.html' - ctx_or_redir = handler() - if str == type(ctx_or_redir): - return ctx_or_redir - assert isinstance(ctx_or_redir, dict) - html = self.server.jinja.get_template(template).render(**ctx_or_redir) - self._send_html(html) + tmpl_name = f'{self._site}' + ctx_or_redir_target = handler() + if isinstance(ctx_or_redir_target, str): + return ctx_or_redir_target + self._send_page(ctx_or_redir_target, tmpl_name) return None @_request_wrapper('POST', 'Unknown POST target') @@ -338,6 +374,7 @@ class TaskHandler(BaseHTTPRequestHandler): todos.sort(key=lambda t: t.date, reverse=True) else: todos.sort(key=lambda t: t.date) + sort_by = 'title' return {'start': start, 'end': end, 'process_id': process_id, 'comment_pattern': comment_pattern, 'todos': todos, 'all_processes': Process.all(self.conn), 'sort_by': sort_by} @@ -355,6 +392,7 @@ class TaskHandler(BaseHTTPRequestHandler): conditions.sort(key=lambda c: c.title.newest, reverse=True) else: conditions.sort(key=lambda c: c.title.newest) + sort_by = 'title' return {'conditions': conditions, 'sort_by': sort_by, 'pattern': pattern} @@ -442,6 +480,7 @@ class TaskHandler(BaseHTTPRequestHandler): processes.sort(key=lambda p: p.title.newest, reverse=True) else: processes.sort(key=lambda p: p.title.newest) + sort_by = 'title' return {'processes': processes, 'sort_by': sort_by, 'pattern': pattern} # POST handlers