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