]> apps.delaporte.us Git - matrix-goal-bot.git/blob - matrix_goal_bot/db.py
533b6840b091617bc5702d51ec464d4c8d6600bd
[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 def migrate(self):
92 with Session(self.engine) as session:
93 session.exec(text(''' alter table goal add start_date DATETIME; '''))
94 session.commit()
95 return 'Success'
96
97
98 def _set_pref_goal_id(self, goal_id):
99 with Session(self.engine) as session:
100 prefs = session.exec(select(PreferGoal)).all()
101 for pref in prefs:
102 session.delete(pref)
103 session.commit()
104 pref = PreferGoal()
105 pref.goal_id = goal_id
106 session.add(pref)
107 session.commit()
108
109 def _get_pref_goal_id(self):
110 with Session(self.engine) as session:
111 pref = session.exec(select(PreferGoal)).one()
112 return pref.goal_id
113
114
115 def clear(self, goal_id, clear_all=False):
116 with Session(self.engine) as session:
117 goal = session.exec(_get_with_id(Goal, goal_id)).first()
118 for item in goal.tasks:
119 if clear_all or item.complete_date:
120 session.delete(item)
121 session.commit()
122
123 def get_all_visions(self):
124 with Session(self.engine) as session:
125 cmd = select(Vision).where(Vision.complete_date == None)
126 return session.exec(cmd).all()
127
128 def get_all_goals(self):
129 '''List all goals'''
130 with Session(self.engine) as session:
131 cmd = select(Goal).where(Goal.complete_date == None)
132 return session.exec(cmd).all()
133
134 def get_current_goals(self):
135 '''List current goals'''
136 with Session(self.engine) as session:
137 cmd = select(Goal).where(Goal.complete_date == None).where(Goal.start_date <= today())
138 # cmd = select(Goal).where(Goal.complete_date == None)
139 return session.exec(cmd).all()
140
141 def get_done_goals(self):
142 '''List completed goals'''
143 with Session(self.engine) as session:
144 cmd = select(Goal).where(Goal.complete_date != None)
145 return session.exec(cmd).all()
146
147
148 def get_goal(self, goal_id):
149 self._set_pref_goal_id(goal_id)
150 with Session(self.engine) as session:
151 cmd = select(Goal).where(Goal.id == goal_id)
152 goal = session.exec(cmd).first()
153 return (goal, goal.tasks)
154
155 def get_vision(self, id):
156 with Session(self.engine) as session:
157 cmd = select(Vision).where(Vision.id == id)
158 vision = session.exec(cmd).first()
159 if vision:
160 return (vision, vision.goals)
161 else:
162 return ('Not found', [])
163
164
165 def complete_vision(self, id):
166 with Session(self.engine) as session:
167 cmd = select(Vision).where(Vision.id == id)
168 vision = session.exec(cmd).first()
169 vision.complete_date = dt.today()
170 session.commit()
171
172
173 def complete_goal(self, goal_id):
174 vision_id = -1
175 with Session(self.engine) as session:
176 cmd = select(Goal).where(Goal.id == goal_id)
177 goal = session.exec(cmd).first()
178 goal.complete_date = dt.today()
179 vision_id = goal.vision_id
180 session.commit()
181 return vision_id
182
183
184 def put_off_goal(self, goal_id):
185 vision_id = -1
186 with Session(self.engine) as session:
187 cmd = select(Goal).where(Goal.id == goal_id)
188 goal = session.exec(cmd).first()
189 goal.start_date = dt.today() + timedelta(days=14)
190 vision_id = goal.vision_id
191 session.commit()
192 return vision_id
193
194 def start_goal(self, goal_id):
195 vision = None
196 with Session(self.engine) as session:
197 cmd = select(Goal).where(Goal.id == goal_id)
198 goal = session.exec(cmd).first()
199 goal.start_date = dt.today()
200 vision_id = goal.vision_id
201 session.commit()
202 if vision:
203 return (vision, vision.goals)
204 else:
205 return ('No Vision Assigned', [])
206
207
208 def rename_goal(self, goal_id, name):
209 self._set_pref_goal_id(goal_id)
210 vision_id = -1
211 with Session(self.engine) as session:
212 cmd = select(Goal).where(Goal.id == goal_id)
213 goal = session.exec(cmd).first()
214 goal.name = name
215 vision_id = goal.vision_id
216 session.commit()
217 return vision_id
218
219
220 def complete_task(self, id):
221 with Session(self.engine) as session:
222 cmd = select(Task).where(Task.id == id)
223 task = session.exec(cmd).first()
224 task.complete_date = dt.today()
225 goal_id = task.goal_id
226 session.commit()
227 self._set_pref_goal_id(goal_id)
228 return goal_id
229
230 def add_with_name(self, cls, name):
231 id = -1
232 with Session(self.engine) as session:
233 new = cls(name=name)
234 session.add(new)
235 session.commit()
236 id = new.id
237 return id
238
239 def add_vision(self, name):
240 return self.add_with_name(Vision, name)
241
242 def add_goal(self, name):
243 goal_id = self.add_with_name(Goal, name)
244 self._set_pref_goal_id(goal_id)
245 return goal_id
246
247 def quick_add_task(self, name):
248 goal_id = self._get_pref_goal_id()
249 task_id = self.add_with_name(Task, name)
250 with Session(self.engine) as session:
251 cmd = select(Task).where(Task.id == task_id)
252 new = session.exec(cmd).first()
253 new.goal_id = goal_id
254 session.commit()
255 return goal_id
256
257 def remove_task(self, task_id):
258 task_name = ''
259 logger.debug(f'Removing task with id {task_id}')
260 with Session(self.engine) as session:
261 cmd = select(Task).where(Task.id == int(task_id))
262 to_remove = session.exec(cmd).first()
263 if not to_remove:
264 return f'Unable to find task with id {task_id}'
265
266 logger.debug(f'Removing task with name {to_remove.name}')
267 task_name = to_remove.name
268 session.delete(to_remove)
269 session.commit()
270 return f'Removed task "{task_name}"'
271
272 def assign_vision(self, goal_id, vision_id):
273 '''Goals may move between visions'''
274 self._set_pref_goal_id(goal_id)
275 with Session(self.engine) as session:
276 cmd = select(Goal).where(Goal.id == goal_id)
277 goal = session.exec(cmd).first()
278 goal.vision_id = vision_id
279 session.commit()
280
281 def visionless(self):
282 '''Get goals with no vision'''
283 with Session(self.engine) as session:
284 cmd = select(Goal).where(Goal.vision_id == None)
285 return session.exec(cmd).all()
286
287
288 def add_note(self, note, goal):
289 '''Notes print with the goal.'''
290 pass
291
292 # Someday: Notes on each
293