]> us-delaporte.pagekite.me Git - matrix-goal-bot.git/blob - matrix_goal_bot/db.py
3f833416a983a18aff675a4416b09c6919369de7
[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=dt.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 <= dt.today())
138 results = session.exec(cmd).all()
139 logger.debug(f'Current goals: {results}')
140 return results
141
142 def get_done_goals(self):
143 '''List completed goals'''
144 with Session(self.engine) as session:
145 cmd = select(Goal).where(Goal.complete_date != None)
146 return session.exec(cmd).all()
147
148
149 def get_goal(self, goal_id):
150 self._set_pref_goal_id(goal_id)
151 with Session(self.engine) as session:
152 cmd = select(Goal).where(Goal.id == goal_id)
153 goal = session.exec(cmd).first()
154 return (goal, goal.tasks)
155
156 def get_vision(self, id):
157 with Session(self.engine) as session:
158 cmd = select(Vision).where(Vision.id == id)
159 vision = session.exec(cmd).first()
160 if vision:
161 return (vision, vision.goals)
162 else:
163 return ('Not found', [])
164
165
166 def complete_vision(self, id):
167 with Session(self.engine) as session:
168 cmd = select(Vision).where(Vision.id == id)
169 vision = session.exec(cmd).first()
170 vision.complete_date = dt.today()
171 session.commit()
172
173
174 def complete_goal(self, goal_id):
175 vision_id = -1
176 with Session(self.engine) as session:
177 cmd = select(Goal).where(Goal.id == goal_id)
178 goal = session.exec(cmd).first()
179 goal.complete_date = dt.today()
180 vision_id = goal.vision_id
181 session.commit()
182 return vision_id
183
184
185 def put_off_goal(self, goal_id):
186 vision_id = -1
187 with Session(self.engine) as session:
188 cmd = select(Goal).where(Goal.id == goal_id)
189 goal = session.exec(cmd).first()
190 goal.start_date = dt.today() + timedelta(days=14)
191 vision_id = goal.vision_id
192 session.commit()
193 return vision_id
194
195 def start_goal(self, goal_id):
196 vision = None
197 with Session(self.engine) as session:
198 cmd = select(Goal).where(Goal.id == goal_id)
199 goal = session.exec(cmd).first()
200 goal.start_date = dt.today()
201 vision_id = goal.vision_id
202 session.commit()
203 if vision:
204 return (vision, vision.goals)
205 else:
206 return ('No Vision Assigned', [])
207
208
209 def rename_goal(self, goal_id, name):
210 self._set_pref_goal_id(goal_id)
211 vision_id = -1
212 with Session(self.engine) as session:
213 cmd = select(Goal).where(Goal.id == goal_id)
214 goal = session.exec(cmd).first()
215 goal.name = name
216 vision_id = goal.vision_id
217 session.commit()
218 return vision_id
219
220
221 def complete_task(self, id):
222 with Session(self.engine) as session:
223 cmd = select(Task).where(Task.id == id)
224 task = session.exec(cmd).first()
225 task.complete_date = dt.today()
226 goal_id = task.goal_id
227 session.commit()
228 self._set_pref_goal_id(goal_id)
229 return goal_id
230
231 def add_with_name(self, cls, name):
232 id = -1
233 with Session(self.engine) as session:
234 new = cls(name=name)
235 session.add(new)
236 session.commit()
237 id = new.id
238 return id
239
240 def add_vision(self, name):
241 return self.add_with_name(Vision, name)
242
243 def add_goal(self, name):
244 goal_id = self.add_with_name(Goal, name)
245 self._set_pref_goal_id(goal_id)
246 return goal_id
247
248 def quick_add_task(self, name):
249 goal_id = self._get_pref_goal_id()
250 task_id = self.add_with_name(Task, name)
251 with Session(self.engine) as session:
252 cmd = select(Task).where(Task.id == task_id)
253 new = session.exec(cmd).first()
254 new.goal_id = goal_id
255 session.commit()
256 return goal_id
257
258 def remove_task(self, task_id):
259 task_name = ''
260 logger.debug(f'Removing task with id {task_id}')
261 with Session(self.engine) as session:
262 cmd = select(Task).where(Task.id == int(task_id))
263 to_remove = session.exec(cmd).first()
264 if not to_remove:
265 return f'Unable to find task with id {task_id}'
266
267 logger.debug(f'Removing task with name {to_remove.name}')
268 task_name = to_remove.name
269 session.delete(to_remove)
270 session.commit()
271 return f'Removed task "{task_name}"'
272
273 def assign_vision(self, goal_id, vision_id):
274 '''Goals may move between visions'''
275 self._set_pref_goal_id(goal_id)
276 with Session(self.engine) as session:
277 cmd = select(Goal).where(Goal.id == goal_id)
278 goal = session.exec(cmd).first()
279 goal.vision_id = vision_id
280 session.commit()
281
282 def visionless(self):
283 '''Get goals with no vision'''
284 with Session(self.engine) as session:
285 cmd = select(Goal).where(Goal.vision_id == None)
286 return session.exec(cmd).all()
287
288
289 def add_note(self, note, goal):
290 '''Notes print with the goal.'''
291 pass
292
293 # Someday: Notes on each
294