From 8f6b4ec61b126d6edbfda4f20d62398d92390a95 Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Fri, 19 Apr 2024 07:55:22 +0200
Subject: [PATCH] Clean up enablers/disablers code and naming conventions.

---
 plomtask/http.py       | 12 +++----
 plomtask/processes.py  | 29 +++++++++--------
 plomtask/todos.py      | 72 +++++++++++++++++++++---------------------
 scripts/init.sql       | 20 ++++++------
 templates/process.html | 14 ++++----
 templates/todo.html    | 16 +++++-----
 tests/processes.py     |  8 ++---
 tests/todos.py         | 32 +++++++++----------
 8 files changed, 102 insertions(+), 101 deletions(-)

diff --git a/plomtask/http.py b/plomtask/http.py
index cc4358c..4bf58b4 100644
--- a/plomtask/http.py
+++ b/plomtask/http.py
@@ -205,13 +205,13 @@ class TaskHandler(BaseHTTPRequestHandler):
             child = Todo.by_id(self.conn, child_id)
             todo.add_child(child)
         todo.set_conditions(self.conn, self.form_data.get_all_int('condition'))
-        todo.set_fulfills(self.conn, self.form_data.get_all_int('fulfills'))
-        todo.set_undoes(self.conn, self.form_data.get_all_int('undoes'))
+        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
         todo.save(self.conn)
-        for condition in todo.fulfills:
+        for condition in todo.enables:
             condition.save(self.conn)
-        for condition in todo.undoes:
+        for condition in todo.disables:
             condition.save(self.conn)
 
     def do_POST_process(self) -> None:
@@ -223,8 +223,8 @@ class TaskHandler(BaseHTTPRequestHandler):
         process.effort.set(self.form_data.get_float('effort'))
         process.set_conditions(self.conn,
                                self.form_data.get_all_int('condition'))
-        process.set_fulfills(self.conn, self.form_data.get_all_int('fulfills'))
-        process.set_undoes(self.conn, self.form_data.get_all_int('undoes'))
+        process.set_enables(self.conn, self.form_data.get_all_int('enables'))
+        process.set_disables(self.conn, self.form_data.get_all_int('disables'))
         process.save_core(self.conn)
         assert process.id_ is not None  # for mypy
         process.explicit_steps = []
diff --git a/plomtask/processes.py b/plomtask/processes.py
index 490acc3..0e8846d 100644
--- a/plomtask/processes.py
+++ b/plomtask/processes.py
@@ -20,8 +20,8 @@ class Process(BaseModel):
         self.effort = VersionedAttribute(self, 'process_efforts', 1.0)
         self.explicit_steps: list[ProcessStep] = []
         self.conditions: list[Condition] = []
-        self.fulfills: list[Condition] = []
-        self.undoes: list[Condition] = []
+        self.enables: list[Condition] = []
+        self.disables: list[Condition] = []
 
     @classmethod
     def all(cls, db_conn: DatabaseConnection) -> list[Process]:
@@ -56,7 +56,7 @@ class Process(BaseModel):
                                          process.id_):
                 step = ProcessStep.from_table_row(db_conn, row)
                 process.explicit_steps += [step]
-            for name in ('conditions', 'fulfills', 'undoes'):
+            for name in ('conditions', 'enables', 'disables'):
                 table = f'process_{name}'
                 for cond_id in db_conn.column_where(table, 'condition',
                                                     'process', process.id_):
@@ -119,14 +119,15 @@ class Process(BaseModel):
         for id_ in ids:
             trgt_list += [Condition.by_id(db_conn, id_)]
 
-    def set_fulfills(self, db_conn: DatabaseConnection,
-                     ids: list[int]) -> None:
-        """Set self.fulfills to Conditions identified by ids."""
-        self.set_conditions(db_conn, ids, 'fulfills')
+    def set_enables(self, db_conn: DatabaseConnection,
+                    ids: list[int]) -> None:
+        """Set self.enables to Conditions identified by ids."""
+        self.set_conditions(db_conn, ids, 'enables')
 
-    def set_undoes(self, db_conn: DatabaseConnection, ids: list[int]) -> None:
-        """Set self.undoes to Conditions identified by ids."""
-        self.set_conditions(db_conn, ids, 'undoes')
+    def set_disables(self, db_conn: DatabaseConnection,
+                     ids: list[int]) -> None:
+        """Set self.disables to Conditions identified by ids."""
+        self.set_conditions(db_conn, ids, 'disables')
 
     def _add_step(self,
                   db_conn: DatabaseConnection,
@@ -184,10 +185,10 @@ class Process(BaseModel):
         self.effort.save(db_conn)
         db_conn.rewrite_relations('process_conditions', 'process', self.id_,
                                   [[c.id_] for c in self.conditions])
-        db_conn.rewrite_relations('process_fulfills', 'process', self.id_,
-                                  [[c.id_] for c in self.fulfills])
-        db_conn.rewrite_relations('process_undoes', 'process', self.id_,
-                                  [[c.id_] for c in self.undoes])
+        db_conn.rewrite_relations('process_enables', 'process', self.id_,
+                                  [[c.id_] for c in self.enables])
+        db_conn.rewrite_relations('process_disables', 'process', self.id_,
+                                  [[c.id_] for c in self.disables])
         db_conn.delete_where('process_steps', 'owner', self.id_)
         for step in self.explicit_steps:
             step.save(db_conn)
diff --git a/plomtask/todos.py b/plomtask/todos.py
index fd72af6..ebe35ac 100644
--- a/plomtask/todos.py
+++ b/plomtask/todos.py
@@ -26,12 +26,12 @@ class Todo(BaseModel):
         self.children: list[Todo] = []
         self.parents: list[Todo] = []
         self.conditions: list[Condition] = []
-        self.fulfills: list[Condition] = []
-        self.undoes: list[Condition] = []
+        self.enables: list[Condition] = []
+        self.disables: list[Condition] = []
         if not self.id_:
             self.conditions = process.conditions[:]
-            self.fulfills = process.fulfills[:]
-            self.undoes = process.undoes[:]
+            self.enables = process.enables[:]
+            self.disables = process.disables[:]
 
     @classmethod
     def from_table_row(cls, db_conn: DatabaseConnection,
@@ -59,7 +59,7 @@ class Todo(BaseModel):
             for t_id in db_conn.column_where('todo_children', 'parent',
                                              'child', id_):
                 todo.parents += [cls.by_id(db_conn, t_id)]
-            for name in ('conditions', 'fulfills', 'undoes'):
+            for name in ('conditions', 'enables', 'disables'):
                 table = f'todo_{name}'
                 for cond_id in db_conn.column_where(table, 'condition',
                                                     'todo', todo.id_):
@@ -76,31 +76,30 @@ class Todo(BaseModel):
             todos += [cls.by_id(db_conn, id_)]
         return todos
 
+    @staticmethod
+    def _x_ablers_for_at(db_conn: DatabaseConnection, name: str,
+                         cond: Condition, date: str) -> list[Todo]:
+        """Collect all Todos of day that [name] condition."""
+        assert isinstance(cond.id_, int)
+        x_ablers = []
+        table = f'todo_{name}'
+        for id_ in db_conn.column_where(table, 'todo', 'condition', cond.id_):
+            todo = Todo.by_id(db_conn, id_)
+            if todo.date == date:
+                x_ablers += [todo]
+        return x_ablers
+
     @classmethod
-    def enablers_for_at(cls, db_conn: DatabaseConnection, condition: Condition,
-                        date: str) -> list[Todo]:
+    def enablers_for_at(cls, db_conn: DatabaseConnection,
+                        condition: Condition, date: str) -> list[Todo]:
         """Collect all Todos of day that enable condition."""
-        assert isinstance(condition.id_, int)
-        enablers = []
-        for id_ in db_conn.column_where('todo_fulfills', 'todo', 'condition',
-                                        condition.id_):
-            todo = cls.by_id(db_conn, id_)
-            if todo.date == date:
-                enablers += [todo]
-        return enablers
+        return cls._x_ablers_for_at(db_conn, 'enables', condition, date)
 
     @classmethod
     def disablers_for_at(cls, db_conn: DatabaseConnection,
                          condition: Condition, date: str) -> list[Todo]:
         """Collect all Todos of day that disable condition."""
-        assert isinstance(condition.id_, int)
-        disablers = []
-        for id_ in db_conn.column_where('todo_undoes', 'todo', 'condition',
-                                        condition.id_):
-            todo = cls.by_id(db_conn, id_)
-            if todo.date == date:
-                disablers += [todo]
-        return disablers
+        return cls._x_ablers_for_at(db_conn, 'disables', condition, date)
 
     @property
     def is_doable(self) -> bool:
@@ -130,19 +129,20 @@ class Todo(BaseModel):
         if self._is_done != value:
             self._is_done = value
             if value is True:
-                for condition in self.fulfills:
+                for condition in self.enables:
                     condition.is_active = True
-                for condition in self.undoes:
+                for condition in self.disables:
                     condition.is_active = False
 
-    def set_undoes(self, db_conn: DatabaseConnection, ids: list[int]) -> None:
-        """Set self.undoes to Conditions identified by ids."""
-        self.set_conditions(db_conn, ids, 'undoes')
-
-    def set_fulfills(self, db_conn: DatabaseConnection,
+    def set_disables(self, db_conn: DatabaseConnection,
                      ids: list[int]) -> None:
-        """Set self.fulfills to Conditions identified by ids."""
-        self.set_conditions(db_conn, ids, 'fulfills')
+        """Set self.disables to Conditions identified by ids."""
+        self.set_conditions(db_conn, ids, 'disables')
+
+    def set_enables(self, db_conn: DatabaseConnection,
+                    ids: list[int]) -> None:
+        """Set self.enables to Conditions identified by ids."""
+        self.set_conditions(db_conn, ids, 'enables')
 
     def set_conditions(self, db_conn: DatabaseConnection, ids: list[int],
                        target: str = 'conditions') -> None:
@@ -181,7 +181,7 @@ class Todo(BaseModel):
                                   [[c.id_] for c in self.children])
         db_conn.rewrite_relations('todo_conditions', 'todo', self.id_,
                                   [[c.id_] for c in self.conditions])
-        db_conn.rewrite_relations('todo_fulfills', 'todo', self.id_,
-                                  [[c.id_] for c in self.fulfills])
-        db_conn.rewrite_relations('todo_undoes', 'todo', self.id_,
-                                  [[c.id_] for c in self.undoes])
+        db_conn.rewrite_relations('todo_enables', 'todo', self.id_,
+                                  [[c.id_] for c in self.enables])
+        db_conn.rewrite_relations('todo_disables', 'todo', self.id_,
+                                  [[c.id_] for c in self.disables])
diff --git a/scripts/init.sql b/scripts/init.sql
index 5fdd779..b2979a5 100644
--- a/scripts/init.sql
+++ b/scripts/init.sql
@@ -34,6 +34,13 @@ CREATE TABLE process_descriptions (
     PRIMARY KEY (parent, timestamp),
     FOREIGN KEY (parent) REFERENCES processes(id)
 );
+CREATE TABLE process_disables (
+    process INTEGER NOT NULL,
+    condition INTEGER NOT NULL,
+    PRIMARY KEY(process, condition),
+    FOREIGN KEY (process) REFERENCES processes(id),
+    FOREIGN KEY (condition) REFERENCES conditions(id)
+);
 CREATE TABLE process_efforts (
     parent INTEGER NOT NULL,
     timestamp TEXT NOT NULL,
@@ -41,7 +48,7 @@ CREATE TABLE process_efforts (
     PRIMARY KEY (parent, timestamp),
     FOREIGN KEY (parent) REFERENCES processes(id)
 );
-CREATE TABLE process_fulfills (
+CREATE TABLE process_enables (
     process INTEGER NOT NULL,
     condition INTEGER NOT NULL,
     PRIMARY KEY(process, condition),
@@ -64,13 +71,6 @@ CREATE TABLE process_titles (
     PRIMARY KEY (parent, timestamp),
     FOREIGN KEY (parent) REFERENCES processes(id)
 );
-CREATE TABLE process_undoes (
-    process INTEGER NOT NULL,
-    condition INTEGER NOT NULL,
-    PRIMARY KEY(process, condition),
-    FOREIGN KEY (process) REFERENCES processes(id),
-    FOREIGN KEY (condition) REFERENCES conditions(id)
-);
 CREATE TABLE processes (
     id INTEGER PRIMARY KEY
 );
@@ -88,14 +88,14 @@ CREATE TABLE todo_conditions (
     FOREIGN KEY (todo) REFERENCES todos(id),
     FOREIGN KEY (condition) REFERENCES conditions(id)
 );
-CREATE TABLE todo_fulfills (
+CREATE TABLE todo_disables (
     todo INTEGER NOT NULL,
     condition INTEGER NOT NULL,
     PRIMARY KEY(todo, condition),
     FOREIGN KEY (todo) REFERENCES todos(id),
     FOREIGN KEY (condition) REFERENCES conditions(id)
 );
-CREATE TABLE todo_undoes (
+CREATE TABLE todo_enables (
     todo INTEGER NOT NULL,
     condition INTEGER NOT NULL,
     PRIMARY KEY(todo, condition),
diff --git a/templates/process.html b/templates/process.html
index b55ee07..85651d7 100644
--- a/templates/process.html
+++ b/templates/process.html
@@ -56,12 +56,12 @@ add condition: <input name="condition" list="condition_candidates" autocomplete=
 <option value="{{condition_candidate.id_}}">{{condition_candidate.title.newest|e}}</option>
 {% endfor %}
 </datalist>
-<h4>fulfills</h4>
+<h4>enables</h4>
 <table>
-{% for condition in process.fulfills %}
+{% for condition in process.enables %}
 <tr>
 <td>
-<input type="checkbox" name="fulfills" value="{{condition.id_}}" checked />
+<input type="checkbox" name="enables" value="{{condition.id_}}" checked />
 </td>
 <td>
 <a href="condition?id={{condition.id_}}">{{condition.title.newest|e}}</a>
@@ -69,13 +69,13 @@ add condition: <input name="condition" list="condition_candidates" autocomplete=
 </tr>
 {% endfor %}
 </table>
-add fulfills: <input name="fulfills" list="condition_candidates" autocomplete="off" />
+add enables: <input name="enables" list="condition_candidates" autocomplete="off" />
 <h4>conditions</h4>
 <table>
-{% for condition in process.undoes %}
+{% for condition in process.disables %}
 <tr>
 <td>
-<input type="checkbox" name="undoes" value="{{condition.id_}}" checked />
+<input type="checkbox" name="disables" value="{{condition.id_}}" checked />
 </td>
 <td>
 <a href="condition?id={{condition.id_}}">{{condition.title.newest|e}}</a>
@@ -83,7 +83,7 @@ add fulfills: <input name="fulfills" list="condition_candidates" autocomplete="o
 </tr>
 {% endfor %}
 </table>
-add undoes: <input name="undoes" list="condition_candidates" autocomplete="off" />
+add disables: <input name="disables" list="condition_candidates" autocomplete="off" />
 <h4>steps</h4>
 <table>
 {% for step_id, step_node in steps.items() %}
diff --git a/templates/todo.html b/templates/todo.html
index 1fa2922..92b0657 100644
--- a/templates/todo.html
+++ b/templates/todo.html
@@ -28,12 +28,12 @@ add condition: <input name="condition" list="condition_candidates" autocomplete=
 <option value="{{condition_candidate.id_}}">{{condition_candidate.title.newest|e}}</option>
 {% endfor %}
 </datalist>
-<h4>fulfills</h4>
+<h4>enables</h4>
 <table>
-{% for condition in todo.fulfills %}
+{% for condition in todo.enables %}
 <tr>
 <td>
-<input type="checkbox" name="fulfills" value="{{condition.id_}}" checked />
+<input type="checkbox" name="enables" value="{{condition.id_}}" checked />
 </td>
 <td>
 <a href="condition?id={{condition.id_}}">{{condition.title.newest|e}}</a>
@@ -41,13 +41,13 @@ add condition: <input name="condition" list="condition_candidates" autocomplete=
 </tr>
 {% endfor %}
 </table>
-add fulfills: <input name="fulfills" list="condition_candidates" autocomplete="off" />
-<h4>undoes</h4>
+add enables: <input name="enables" list="condition_candidates" autocomplete="off" />
+<h4>disables</h4>
 <table>
-{% for condition in todo.undoes%}
+{% for condition in todo.disables%}
 <tr>
 <td>
-<input type="checkbox" name="undoes" value="{{condition.id_}}" checked />
+<input type="checkbox" name="disables" value="{{condition.id_}}" checked />
 </td>
 <td>
 <a href="condition?id={{condition.id_}}">{{condition.title.newest|e}}</a>
@@ -55,7 +55,7 @@ add fulfills: <input name="fulfills" list="condition_candidates" autocomplete="o
 </tr>
 {% endfor %}
 </table>
-add undoes: <input name="undoes" list="condition_candidates" autocomplete="off" />
+add disables: <input name="disables" list="condition_candidates" autocomplete="off" />
 <h4>parents</h4>
 <ul>
 {% for parent in todo.parents %}
diff --git a/tests/processes.py b/tests/processes.py
index 491a48f..084cfe0 100644
--- a/tests/processes.py
+++ b/tests/processes.py
@@ -108,8 +108,8 @@ class TestsWithDB(TestCaseWithDB):
                          [self.proc1, self.proc2])
 
     def test_Process_conditions(self) -> None:
-        """Test setting Process.conditions/fulfills/undoes."""
-        for target in ('conditions', 'fulfills', 'undoes'):
+        """Test setting Process.conditions/enables/disables."""
+        for target in ('conditions', 'enables', 'disables'):
             c1 = Condition(None, False)
             c1.save(self.db_conn)
             assert isinstance(c1.id_, int)
@@ -195,9 +195,9 @@ class TestsWithServer(TestCaseWithServer):
         form_data_cond = {'title': 'foo', 'description': 'foo'}
         self.check_post(form_data_cond, '/condition', 302, '/')
         self.check_post(form_data, '/process?id=', 302, '/')
-        form_data['undoes'] = [1]
+        form_data['disables'] = [1]
         self.check_post(form_data, '/process?id=', 302, '/')
-        form_data['fulfills'] = [1]
+        form_data['enables'] = [1]
         self.check_post(form_data, '/process?id=', 302, '/')
 
     def test_do_GET(self) -> None:
diff --git a/tests/todos.py b/tests/todos.py
index 426bb91..c704c27 100644
--- a/tests/todos.py
+++ b/tests/todos.py
@@ -55,18 +55,18 @@ class TestsWithDB(TestCaseWithDB):
         todo.set_conditions(self.db_conn, [self.cond2.id_])
         self.assertEqual(todo.conditions, [self.cond2])
         self.assertEqual(self.proc.conditions, [self.cond1])
-        self.proc.set_fulfills(self.db_conn, [self.cond1.id_])
+        self.proc.set_enables(self.db_conn, [self.cond1.id_])
         todo = Todo(None, self.proc, False, self.date1)
-        self.assertEqual(todo.fulfills, [self.cond1])
-        todo.set_fulfills(self.db_conn, [self.cond2.id_])
-        self.assertEqual(todo.fulfills, [self.cond2])
-        self.assertEqual(self.proc.fulfills, [self.cond1])
-        self.proc.set_undoes(self.db_conn, [self.cond1.id_])
+        self.assertEqual(todo.enables, [self.cond1])
+        todo.set_enables(self.db_conn, [self.cond2.id_])
+        self.assertEqual(todo.enables, [self.cond2])
+        self.assertEqual(self.proc.enables, [self.cond1])
+        self.proc.set_disables(self.db_conn, [self.cond1.id_])
         todo = Todo(None, self.proc, False, self.date1)
-        self.assertEqual(todo.undoes, [self.cond1])
-        todo.set_undoes(self.db_conn, [self.cond2.id_])
-        self.assertEqual(todo.undoes, [self.cond2])
-        self.assertEqual(self.proc.undoes, [self.cond1])
+        self.assertEqual(todo.disables, [self.cond1])
+        todo.set_disables(self.db_conn, [self.cond2.id_])
+        self.assertEqual(todo.disables, [self.cond2])
+        self.assertEqual(self.proc.disables, [self.cond1])
 
     def test_Todo_on_conditions(self) -> None:
         """Test effect of Todos on Conditions."""
@@ -74,8 +74,8 @@ class TestsWithDB(TestCaseWithDB):
         assert isinstance(self.cond2.id_, int)
         todo = Todo(None, self.proc, False, self.date1)
         todo.save(self.db_conn)
-        todo.set_fulfills(self.db_conn, [self.cond1.id_])
-        todo.set_undoes(self.db_conn, [self.cond2.id_])
+        todo.set_enables(self.db_conn, [self.cond1.id_])
+        todo.set_disables(self.db_conn, [self.cond2.id_])
         todo.is_done = True
         self.assertEqual(self.cond1.is_active, True)
         self.assertEqual(self.cond2.is_active, False)
@@ -89,16 +89,16 @@ class TestsWithDB(TestCaseWithDB):
         assert isinstance(self.cond2.id_, int)
         todo1 = Todo(None, self.proc, False, self.date1)
         todo1.save(self.db_conn)
-        todo1.set_fulfills(self.db_conn, [self.cond1.id_])
-        todo1.set_undoes(self.db_conn, [self.cond2.id_])
+        todo1.set_enables(self.db_conn, [self.cond1.id_])
+        todo1.set_disables(self.db_conn, [self.cond2.id_])
         todo1.save(self.db_conn)
         todo2 = Todo(None, self.proc, False, self.date1)
         todo2.save(self.db_conn)
-        todo2.set_fulfills(self.db_conn, [self.cond2.id_])
+        todo2.set_enables(self.db_conn, [self.cond2.id_])
         todo2.save(self.db_conn)
         todo3 = Todo(None, self.proc, False, self.date2)
         todo3.save(self.db_conn)
-        todo3.set_fulfills(self.db_conn, [self.cond2.id_])
+        todo3.set_enables(self.db_conn, [self.cond2.id_])
         todo3.save(self.db_conn)
         enablers = Todo.enablers_for_at(self.db_conn, self.cond1, self.date1)
         self.assertEqual(enablers, [todo1])
-- 
2.30.2