"""Web server stuff."""
from __future__ import annotations
from dataclasses import dataclass
-from typing import Any, Callable
+from typing import Any, Callable, Mapping
from base64 import b64encode, b64decode
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
_form_data: InputsParser
_params: InputsParser
- def _send_html(self, html: str, code: int = 200) -> None:
+ def _send_html(self,
+ tmpl_name: str,
+ ctx: Mapping[str, object],
+ code: int = 200) -> None:
"""Send HTML as proper HTTP response."""
+ tmpl = self.server.jinja.get_template(tmpl_name)
+ html = tmpl.render(ctx)
self.send_response(code)
self.end_headers()
self.wfile.write(bytes(html, 'utf-8'))
msg = f'{not_found_msg}: {self._site}'
raise NotFoundException(msg)
except HandledException as error:
- html = self.server.jinja.\
- get_template('msg.html').render(msg=error)
- self._send_html(html, error.http_code)
+ for cls in (Day, Todo, Condition, Process, ProcessStep):
+ assert hasattr(cls, 'empty_cache')
+ cls.empty_cache()
+ ctx = {'msg': error}
+ self._send_html('msg.html', ctx, error.http_code)
finally:
self.conn.close()
return wrapper
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'
+ tmpl_name = f'{self._site}.html'
ctx_or_redir = handler()
- if str == type(ctx_or_redir):
+ if isinstance(ctx_or_redir, str):
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)
+ self._send_html(tmpl_name, ctx_or_redir)
return None
@_request_wrapper('POST', 'Unknown POST target')
ret = Day.by_date_range_with_limits(self.conn, (start, end), 'id')
days, start, end = ret
days = Day.with_filled_gaps(days, start, end)
- for day in days:
- day.collect_calendarized_todos(self.conn)
today = date_in_n_days(0)
return {'start': start, 'end': end, 'days': days, 'today': today}
def do_GET_day(self) -> dict[str, object]:
"""Show single Day of ?date=."""
date = self._params.get_str('date', date_in_n_days(0))
+ day = Day.by_id(self.conn, date, create=True)
make_type = self._params.get_str('make_type')
- todays_todos = Todo.by_date(self.conn, date)
conditions_present = []
enablers_for = {}
disablers_for = {}
- for todo in todays_todos:
+ for todo in day.todos:
for condition in todo.conditions + todo.blockers:
if condition not in conditions_present:
conditions_present += [condition]
if condition in p.disables]
seen_todos: set[int] = set()
top_nodes = [t.get_step_tree(seen_todos)
- for t in todays_todos if not t.parents]
- return {'day': Day.by_id(self.conn, date, create=True),
- 'total_effort': Todo.total_effort_at_date(self.conn, date),
+ for t in day.todos if not t.parents]
+ return {'day': day,
'top_nodes': top_nodes,
'make_type': make_type,
'enablers_for': enablers_for,
if len(efforts) > 0:
todo.effort = float(efforts[i]) if efforts[i] else None
todo.save(self.conn)
- for condition in todo.enables:
- condition.save(self.conn)
- for condition in todo.disables:
- condition.save(self.conn)
return f'/day?date={date}&make_type={make_type}'
def do_POST_todo(self) -> str:
todo.calendarize = len(self._form_data.get_all_str('calendarize')) > 0
todo.comment = self._form_data.get_str('comment', ignore_strict=True)
todo.save(self.conn)
- for condition in todo.enables:
- condition.save(self.conn)
- for condition in todo.disables:
- condition.save(self.conn)
return f'/todo?id={todo.id_}'
def do_POST_process_descriptions(self) -> str:
None)]
except ValueError:
new_step_title = step_identifier
- process.uncache()
process.set_steps(self.conn, steps)
process.set_step_suppressions(self.conn,
self._form_data.
get_all_int('suppresses'))
- process.save(self.conn)
owners_to_set = []
new_owner_title = None
for owner_identifier in self._form_data.get_all_str('step_of'):
elif new_owner_title:
title_b64_encoded = b64encode(new_owner_title.encode()).decode()
params = f'has_step={process.id_}&title_b64={title_b64_encoded}'
+ process.save(self.conn)
return f'/process?{params}'
def do_POST_condition_descriptions(self) -> str: