X-Git-Url: https://plomlompom.com/repos/todo?a=blobdiff_plain;f=plomtask%2Fhttp.py;h=18b77a6f0a97ccea4718261f69e23be7ab9d3866;hb=244270eed71df45faf9554d0666b816be9876f77;hp=7c7fbd408edeb47dd48b9a4a04f93beca085f70a;hpb=8f28c8c685fa91b9cbabb4b424da4091e52058cf;p=plomtask diff --git a/plomtask/http.py b/plomtask/http.py index 7c7fbd4..18b77a6 100644 --- a/plomtask/http.py +++ b/plomtask/http.py @@ -11,13 +11,12 @@ 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 from plomtask.days import Day -from plomtask.exceptions import HandledException, BadFormatException, \ - NotFoundException +from plomtask.exceptions import (HandledException, BadFormatException, + NotFoundException) 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' @@ -42,15 +41,25 @@ class TaskServer(HTTPServer): def ctx_to_json(ctx: dict[str, object]) -> str: """Render ctx into JSON string.""" def walk_ctx(node: object) -> Any: - if isinstance(node, BaseModel): + if hasattr(node, 'as_dict_into_reference'): + if hasattr(node, 'id_') and node.id_ is not None: + return node.as_dict_into_reference(library) + if hasattr(node, 'as_dict'): return node.as_dict if isinstance(node, (list, tuple)): return [walk_ctx(x) for x in node] + if isinstance(node, dict): + d = {} + for k, v in node.items(): + d[k] = walk_ctx(v) + return d if isinstance(node, HandledException): return str(node) return node + library: dict[str, dict[str | int, object]] = {} for k, v in ctx.items(): ctx[k] = walk_ctx(v) + ctx['_library'] = library return json_dumps(ctx) def render(self, ctx: dict[str, object], tmpl_name: str = '') -> str: @@ -143,7 +152,7 @@ class TaskHandler(BaseHTTPRequestHandler): tmpl_name: str, code: int = 200 ) -> None: - """Send HTML as proper HTTP response.""" + """Send ctx as proper HTTP response.""" body = self.server.render(ctx, tmpl_name) self.send_response(code) for header_tuple in self.server.headers: @@ -486,6 +495,32 @@ class TaskHandler(BaseHTTPRequestHandler): # POST handlers + @staticmethod + def _delete_or_post(target_class: Any, redir_target: str = '/' + ) -> Callable[..., Callable[[TaskHandler], str]]: + def decorator(f: Callable[..., str] + ) -> Callable[[TaskHandler], str]: + def wrapper(self: TaskHandler) -> str: + # pylint: disable=protected-access + # (because pylint here fails to detect the use of wrapper as a + # method to self with respective access privileges) + id_ = self._params.get_int_or_none('id') + for _ in self._form_data.get_all_str('delete'): + if id_ is None: + msg = 'trying to delete non-saved ' +\ + f'{target_class.__name__}' + raise NotFoundException(msg) + item = target_class.by_id(self.conn, id_) + item.remove(self.conn) + return redir_target + if target_class.can_create_by_id: + item = target_class.by_id_or_create(self.conn, id_) + else: + item = target_class.by_id(self.conn, id_) + return f(self, item) + return wrapper + return decorator + def _change_versioned_timestamps(self, cls: Any, attr_name: str) -> str: """Update history timestamps for VersionedAttribute.""" id_ = self._params.get_int_or_none('id') @@ -496,8 +531,7 @@ class TaskHandler(BaseHTTPRequestHandler): if old[19:] != v: attr.reset_timestamp(old, f'{v}.0') attr.save(self.conn) - cls_name = cls.__name__.lower() - return f'/{cls_name}_{attr_name}s?id={item.id_}' + return f'/{cls.name_lowercase()}_{attr_name}s?id={item.id_}' def do_POST_day(self) -> str: """Update or insert Day of date and Todos mapped to it.""" @@ -526,16 +560,9 @@ class TaskHandler(BaseHTTPRequestHandler): todo.save(self.conn) return f'/day?date={date}&make_type={make_type}' - def do_POST_todo(self) -> str: + @_delete_or_post(Todo, '/') + def do_POST_todo(self, todo: Todo) -> str: """Update Todo and its children.""" - # pylint: disable=too-many-locals - # pylint: disable=too-many-branches - id_ = self._params.get_int('id') - for _ in self._form_data.get_all_str('delete'): - todo = Todo .by_id(self.conn, id_) - todo.remove(self.conn) - return '/' - todo = Todo.by_id(self.conn, id_) adopted_child_ids = self._form_data.get_all_int('adopt') processes_to_make_full = self._form_data.get_all_int('make_full') processes_to_make_empty = self._form_data.get_all_int('make_empty') @@ -571,8 +598,8 @@ class TaskHandler(BaseHTTPRequestHandler): effort = self._form_data.get_str('effort', ignore_strict=True) todo.effort = float(effort) if effort else None todo.set_conditions(self.conn, - self._form_data.get_all_int('condition')) - todo.set_blockers(self.conn, self._form_data.get_all_int('blocker')) + self._form_data.get_all_int('conditions')) + todo.set_blockers(self.conn, self._form_data.get_all_int('blockers')) todo.set_enables(self.conn, self._form_data.get_all_int('enables')) todo.set_disables(self.conn, self._form_data.get_all_int('disables')) todo.is_done = len(self._form_data.get_all_str('done')) > 0 @@ -593,23 +620,16 @@ class TaskHandler(BaseHTTPRequestHandler): """Update history timestamps for Process.title.""" return self._change_versioned_timestamps(Process, 'title') - def do_POST_process(self) -> str: + @_delete_or_post(Process, '/processes') + def do_POST_process(self, process: Process) -> str: """Update or insert Process of ?id= and fields defined in postvars.""" - # pylint: disable=too-many-branches - id_ = self._params.get_int_or_none('id') - for _ in self._form_data.get_all_str('delete'): - if id_ is None: - raise NotFoundException('trying to delete non-saved Process') - process = Process.by_id(self.conn, id_) - process.remove(self.conn) - return '/processes' - process = Process.by_id_or_create(self.conn, id_) process.title.set(self._form_data.get_str('title')) process.description.set(self._form_data.get_str('description')) process.effort.set(self._form_data.get_float('effort')) process.set_conditions(self.conn, - self._form_data.get_all_int('condition')) - process.set_blockers(self.conn, self._form_data.get_all_int('blocker')) + self._form_data.get_all_int('conditions')) + process.set_blockers(self.conn, + self._form_data.get_all_int('blockers')) process.set_enables(self.conn, self._form_data.get_all_int('enables')) process.set_disables(self.conn, self._form_data.get_all_int('disables')) @@ -672,16 +692,9 @@ class TaskHandler(BaseHTTPRequestHandler): """Update history timestamps for Condition.title.""" return self._change_versioned_timestamps(Condition, 'title') - def do_POST_condition(self) -> str: + @_delete_or_post(Condition, '/conditions') + def do_POST_condition(self, condition: Condition) -> str: """Update/insert Condition of ?id= and fields defined in postvars.""" - id_ = self._params.get_int_or_none('id') - for _ in self._form_data.get_all_str('delete'): - if id_ is None: - raise NotFoundException('trying to delete non-saved Condition') - condition = Condition.by_id_or_create(self.conn, id_) - condition.remove(self.conn) - return '/conditions' - condition = Condition.by_id_or_create(self.conn, id_) condition.is_active = self._form_data.get_str('is_active') == 'True' condition.title.set(self._form_data.get_str('title')) condition.description.set(self._form_data.get_str('description'))