]> us-delaporte.pagekite.me Git - matrix-goal-bot.git/blob - matrix_goal_bot/db.py
eef5acedf2da4f59aa60c29f75e5a9ff45dc7cbf
[matrix-goal-bot.git] / matrix_goal_bot / db.py
1 import logging
2 import os
3 from datetime import datetime as dt
4
5 from sqlmodel import Field, Session, SQLModel, create_engine, select, text, Relationship
6
7 logger = logging.getLogger(__name__)
8
9 DATE_FORMAT = '%Y-%m-%d'
10
11 def today():
12 return dt.now().strftime(DATE_FORMAT)
13
14
15 class Vision(SQLModel, table=True):
16 id: int | None = Field(default=None, primary_key=True)
17 name: str = Field(default=None, unique=True)
18 complete_date: dt | None = Field(default=None)
19 goals: list["Goal"] = Relationship(back_populates="vision")
20 def __str__(self):
21 return f'{self.name} (Vision {self.id})'
22
23
24 class PreferGoal(SQLModel, table=True):
25 goal_id: int | None = Field(default=None, foreign_key="goal.id", primary_key=True)
26
27
28 class Goal(SQLModel, table=True):
29 id: int | None = Field(default=None, primary_key=True)
30 name: str = Field(default=None, unique=True)
31 # start_date: dt | None = Field(default=today())
32 complete_date: dt | None = Field(default=None)
33 vision_id: int | None = Field(default=None, foreign_key="vision.id")
34 notes: str | None = Field(default=None)
35 tasks: list["Task"] = Relationship(back_populates="goal")
36 vision: Vision = Relationship(back_populates="goals")
37 def __str__(self):
38 if not self.complete_date:
39 return f'{self.name} (Goal {self.id})'
40 else:
41 completed = self.complete_date.strftime(DATE_FORMAT)
42 return f'(Done {completed}) {self.name} (Goal {self.id})'
43
44 class Task(SQLModel, table=True):
45 id: int | None = Field(default=None, primary_key=True)
46 name: str = Field(default=None, unique=True)
47 goal_id: int | None = Field(default=None, foreign_key="goal.id")
48 complete_date: dt | None = Field(default=None)
49 goal: Goal = Relationship(back_populates="tasks")
50 def __str__(self):
51 return f'{self.name} ({self.id})'
52
53
54 def pretty_print(goal, tasks):
55 results = []
56 results.append(f' ## {goal}')
57 if not tasks:
58 results.append('-- Nothing to list --')
59
60 for task in tasks:
61 if(task.complete_date):
62 results.append(f' - [x] {task}')
63 else:
64 results.append(f' - [ ] {task}')
65 return results
66
67
68 def _get_with_id(cls, item_id):
69 return select(cls).where(cls.id == item_id)
70
71 def _get_with_name(cls, name):
72 return select(cls).where(func.lower(cls.name) == func.lower(name))
73
74
75 class Data():
76 def __init__(self, db_file=None):
77 if not db_file:
78 db_file = os.path.join(os.environ.get('MATRIX_DATA_DIR', ''), 'goal.db')
79
80 self.file = db_file
81 self.engine = self.get_engine()
82
83
84 def get_engine(self):
85 return create_engine(f"sqlite:///{self.file}")
86
87 def setup(self):
88 SQLModel.metadata.create_all(self.engine)
89 return 'Success'
90
91
92 def _set_pref_goal_id(self, goal_id):
93 with Session(self.engine) as session:
94 prefs = session.exec(select(PreferGoal)).all()
95 for pref in prefs:
96 session.delete(pref)
97 session.commit()
98 pref = PreferGoal()
99 pref.goal_id = goal_id
100 session.add(pref)
101 session.commit()
102
103 def _get_pref_goal_id(self):
104 with Session(self.engine) as session:
105 pref = session.exec(select(PreferGoal)).one()
106 return pref.goal_id
107
108
109 def clear(self, goal_id, clear_all=False):
110 with Session(self.engine) as session:
111 goal = session.exec(_get_with_id(Goal, goal_id)).first()
112 for item in goal.tasks:
113 if clear_all or item.complete_date:
114 session.delete(item)
115 session.commit()
116
117 def get_all_visions(self):
118 with Session(self.engine) as session:
119 cmd = select(Vision).where(Vision.complete_date == None)
120 return session.exec(cmd).all()
121
122 def get_all_goals(self):
123 '''List all goals'''
124 with Session(self.engine) as session:
125 cmd = select(Goal).where(Goal.complete_date == None)
126 return session.exec(cmd).all()
127
128 def get_current_goals(self):
129 '''List current goals'''
130 with Session(self.engine) as session:
131 # cmd = select(Goal).where(Goal.complete_date == None).where(Goal.start_date <= today())
132 cmd = select(Goal).where(Goal.complete_date == None)
133 return session.exec(cmd).all()
134
135 def get_done_goals(self):
136 '''List completed goals'''
137 with Session(self.engine) as session:
138 cmd = select(Goal).where(Goal.complete_date != None)
139 return session.exec(cmd).all()
140
141
142 def get_goal(self, goal_id):
143 self._set_pref_goal_id(goal_id)
144 with Session(self.engine) as session:
145 cmd = select(Goal).where(Goal.id == goal_id)
146 goal = session.exec(cmd).first()
147 return (goal, goal.tasks)
148
149 def get_vision(self, id):
150 with Session(self.engine) as session:
151 cmd = select(Vision).where(Vision.id == id)
152 vision = session.exec(cmd).first()
153 if vision:
154 return (vision, vision.goals)
155 else:
156 return ('Not found', [])
157
158
159 def complete_vision(self, id):
160 with Session(self.engine) as session:
161 cmd = select(Vision).where(Vision.id == id)
162 vision = session.exec(cmd).first()
163 vision.complete_date = dt.today()
164 session.commit()
165
166
167 def complete_goal(self, goal_id):
168 vision_id = -1
169 with Session(self.engine) as session:
170 cmd = select(Goal).where(Goal.id == goal_id)
171 goal = session.exec(cmd).first()
172 goal.complete_date = dt.today()
173 vision_id = goal.vision_id
174 session.commit()
175 return vision_id
176
177
178 def put_off_goal(self, goal_id):
179 vision_id = -1
180 with Session(self.engine) as session:
181 cmd = select(Goal).where(Goal.id == goal_id)
182 goal = session.exec(cmd).first()
183 goal.start_date = dt.today() + timedelta(days=14)
184 vision_id = goal.vision_id
185 session.commit()
186 return vision_id
187
188
189 def rename_goal(self, goal_id, name):
190 self._set_pref_goal_id(goal_id)
191 vision_id = -1
192 with Session(self.engine) as session:
193 cmd = select(Goal).where(Goal.id == goal_id)
194 goal = session.exec(cmd).first()
195 goal.name = name
196 vision_id = goal.vision_id
197 session.commit()
198 return vision_id
199
200
201 def complete_task(self, id):
202 with Session(self.engine) as session:
203 cmd = select(Task).where(Task.id == id)
204 task = session.exec(cmd).first()
205 task.complete_date = dt.today()
206 goal_id = task.goal_id
207 session.commit()
208 self._set_pref_goal_id(goal_id)
209 return goal_id
210
211 def add_with_name(self, cls, name):
212 id = -1
213 with Session(self.engine) as session:
214 new = cls(name=name)
215 session.add(new)
216 session.commit()
217 id = new.id
218 return id
219
220 def add_vision(self, name):
221 return self.add_with_name(Vision, name)
222
223 def add_goal(self, name):
224 goal_id = self.add_with_name(Goal, name)
225 self._set_pref_goal_id(goal_id)
226 return goal_id
227
228 def quick_add_task(self, name):
229 goal_id = self._get_pref_goal_id()
230 task_id = self.add_with_name(Task, name)
231 with Session(self.engine) as session:
232 cmd = select(Task).where(Task.id == task_id)
233 new = session.exec(cmd).first()
234 new.goal_id = goal_id
235 session.commit()
236 return goal_id
237
238 def remove_task(self, task_id):
239 task_name = ''
240 logger.debug(f'Removing task with id {task_id}')
241 with Session(self.engine) as session:
242 cmd = select(Task).where(Task.id == int(task_id))
243 to_remove = session.exec(cmd).first()
244 if not to_remove:
245 return f'Unable to find task with id {task_id}'
246
247 logger.debug(f'Removing task with name {to_remove.name}')
248 task_name = to_remove.name
249 session.delete(to_remove)
250 session.commit()
251 return f'Removed task "{task_name}"'
252
253 def assign_vision(self, goal_id, vision_id):
254 '''Goals may move between visions'''
255 self._set_pref_goal_id(goal_id)
256 with Session(self.engine) as session:
257 cmd = select(Goal).where(Goal.id == goal_id)
258 goal = session.exec(cmd).first()
259 goal.vision_id = vision_id
260 session.commit()
261
262 def visionless(self):
263 '''Get goals with no vision'''
264 with Session(self.engine) as session:
265 cmd = select(Goal).where(Goal.vision_id == None)
266 return session.exec(cmd).all()
267
268
269 def add_note(self, note, goal):
270 '''Notes print with the goal.'''
271 pass
272
273 # Someday: Notes on each
274