]> apps.delaporte.us Git - matrix-goal-bot.git/blob - matrix_goal_bot/bot.py
Nicer output after later
[matrix-goal-bot.git] / matrix_goal_bot / bot.py
1 '''
2 Prefix: .goal
3
4 Synax:
5 .goal COMMAND ARGS
6
7 Commands:
8 help - show this help
9 extra.help - show extended help
10 add - add a goal
11 clear - clear completed tasks under current goal
12 task ID - add a task under the goal specified by ID
13 close ID - mark goal done by ID
14 done ID - mark task done by ID
15 list - list incomplete goals
16 print GOAL_ID - print a goal and all tasks
17 '''
18
19 ex_help = '''
20 More commands:
21 add.vision - add a new vision (collection of goals)
22 close.vision ID - mark vision as complete by ID
23 dump - dump the full data set - BEWARE - so many messages
24 later VISION_ID - put off all goals in VISION for 14 days
25 list.later - list all 'later' goals
26 print.vision ID - print a vision and all goals
27 set.vision GOAL_ID VISION_ID- associate GOAL_ID with VISION_ID
28 visions - list incomplete visions
29 list.done - list completed goals
30 remove ID - remove a task by ID
31 start GOAL_ID - un-put-off a goal (reverse of later)
32 visionless - list goals with no set vision
33 wins - list recently completed goals
34 '''
35
36
37 from datetime import datetime as dt
38 import logging
39 import os
40
41 import simplematrixbotlib as botlib
42
43 from .db import Data, pretty_print
44
45 DATE_FORMAT = '%Y-%m-%d'
46
47 def today():
48 return dt.now().strftime(DATE_FORMAT)
49
50 logger = logging.getLogger(__name__)
51
52 snark = [
53 'Ye cannot get ye flask.',
54 'Ye flask must be load bearing, or something...',
55 '''You have:
56 no tea
57 ''',
58 'How are you gentlemen?',
59 'All your base are belong to us.',
60 'You have been eaten by a groo.'
61 ]
62
63 class GoalBot():
64 def __init__(self, matrix_server,
65 bot_name,
66 bot_pwd,
67 db_file=None,
68 bot_prefix='.goal'):
69
70 creds = botlib.Creds(matrix_server, bot_name, bot_pwd)
71 self.bot = botlib.Bot(creds)
72 self.prefix = bot_prefix
73 self.data = Data(db_file)
74
75 def run(self):
76 logger.debug('Running goal bot...')
77 self.bot.run()
78
79 async def handle_message(self, room, message):
80 match = botlib.MessageMatch(room, message, self.bot, self.prefix)
81
82 if not match.is_not_from_this_bot():
83 # Let's not talk to our-self
84 return
85
86 logger.debug(f'Message: {message}')
87 if not match.prefix():
88 logger.debug(f'{message} - did not match {self.prefix}')
89
90 if match.prefix():
91 try:
92 result_lines = await self._handle_match(match)
93 for line in result_lines:
94 await self.bot.api.send_text_message(
95 room.room_id, str(line))
96 except Exception as ex:
97 logger.warn(f'Caught exception: {str(ex)}')
98 dumb_msg_idx = len(str(ex)) % len(snark)
99 dumb_msg = snark[dumb_msg_idx]
100 await self.bot.api.send_text_message(
101 room.room_id, dumb_msg)
102
103 await self.bot.api.send_text_message(
104 room.room_id, str(ex))
105
106
107 async def _handle_match(self, match):
108 logger.debug(f'Try to match {str(match)}')
109
110 if match.command('setup'):
111 result = self.data.setup()
112 return [result]
113
114 if match.command('add'):
115 new = ' '.join(match.args()[1:])
116 goal_id = self.data.add_goal(new)
117 results = [f'Goal added with id {goal_id}']
118
119 goals = self.data.get_all_goals()
120 results.append('# Goals list...')
121 for goal in goals:
122 results.append(str(goal))
123
124 return results
125
126 if match.command('list'):
127 logger.debug('Asked to list current goals...')
128 goals = self.data.get_current_goals()
129 results = ['# Goals list...']
130 for goal in goals:
131 results.append(str(goal))
132 return results
133
134
135 if match.command('list.done'):
136 goals = self.data.get_done_goals()
137 results = ['# Completed Goals...']
138 for goal in goals:
139 results.append(str(goal))
140 return results
141
142 if match.command('task'):
143 new = ' '.join(match.args()[1:])
144 goal_id = self.data.quick_add_task(new)
145 goal,tasks = self.data.get_goal(goal_id)
146 results = pretty_print(goal, tasks)
147 return results
148
149 if match.command('add.vision'):
150 new = ' '.join(match.args()[1:])
151 result = self.data.add_vision(new)
152 return [f'Vision added with id {result}']
153
154 if match.command('print'):
155 if len(match.args()) > 1:
156 goal_id = int(match.args()[1])
157 else:
158 goal_id = self.data._get_pref_goal_id()
159
160 logger.debug(f'Searching for goal {goal_id}...')
161 goal,tasks = self.data.get_goal(goal_id)
162 results = pretty_print(goal, tasks)
163
164 return results
165
166
167 if match.command('print.vision'):
168 get_id = int(match.args()[1])
169 vision,goals = self.data.get_vision(get_id)
170 results = pretty_print(vision, goals)
171 return results
172
173 if match.command('close'):
174 goal_id = int(match.args()[1])
175 vision_id = self.data.complete_goal(goal_id)
176 vision,goals = self.data.get_vision(vision_id)
177 results = pretty_print(vision, goals)
178 return results
179
180
181 if match.command('clear'):
182 if len(match.args()) > 1:
183 goal_id = int(match.args()[1])
184 else:
185 goal_id = self.data._get_pref_goal_id()
186 _ = self.data.clear(goal_id)
187
188 goal,tasks = self.data.get_goal(goal_id)
189 results = pretty_print(goal, tasks)
190 return results
191
192
193 if match.command('start'):
194 goal_id = int(match.args()[1])
195 vision,goals = self.data.start_goal(goal_id)
196 results = pretty_print(vision, goals)
197 return results
198
199 if match.command('later'):
200 vision_id = int(match.args()[1])
201 self.data.put_off_vision(vision_id)
202 # Want to see what we just cleaned up
203 goals = self.data.get_current_goals()
204 results = ['# Goals list...']
205 for goal in goals:
206 results.append(str(goal))
207 return results
208
209
210 if match.command('close.vision'):
211 vision_id = int(match.args()[1])
212 self.data.complete_vision(vision_id)
213 vision,goals = self.data.get_vision(vision_id)
214 results = pretty_print(vision, goals)
215 return results
216
217 if match.command('done'):
218 ids = match.args()[1:]
219 for task_id in ids:
220 goal_id = self.data.complete_task(int(task_id))
221 # Print the goal of the last closed task
222 goal,tasks = self.data.get_goal(goal_id)
223 results = pretty_print(goal, tasks)
224 return results
225
226 if match.command('dump'):
227 goals = self.data.get_all_goals()
228 results = ['# Everything ... ']
229 for goal in goals:
230 _,tasks = self.data.get_goal(goal.id)
231 details = pretty_print(goal, tasks)
232 results += details
233 return results
234
235
236 if match.command('list.later'):
237 goals = self.data.get_all_goals()
238 results = ['# All Goals ... ']
239 return results
240
241 if match.command('visions'):
242 items = self.data.get_all_visions()
243 results = ['# Visions']
244 if not items:
245 results.append('-- No current visions --')
246
247 for item in items:
248 results.append(item)
249 return results
250
251 if match.command('visionless'):
252 items = self.data.visionless()
253 results = ['# Goals with no vision']
254 if not items:
255 results.append('-- No visionless goals --')
256
257 for item in items:
258 results.append(item)
259 return results
260
261 if match.command('wins'):
262 items = self.data.wins()
263 results = ['# Wins']
264 if not items:
265 results.append('-- No wins yet --')
266
267 for item in items:
268 results.append(item)
269 return results
270
271
272
273 if match.command('set.vision'):
274 goal_id = int(match.args()[1])
275 vision_id = int(match.args()[2])
276 self.data.assign_vision(goal_id=goal_id, vision_id=vision_id)
277 vision,goals = self.data.get_vision(vision_id)
278 results = pretty_print(vision, goals)
279 return results
280
281
282 if match.command('rename'):
283 goal_id = int(match.args()[1])
284 name = ' '.join(match.args()[2:])
285 self.data.rename_goal(goal_id=goal_id, name=name)
286 goal,tasks = self.data.get_goal(goal_id)
287 results = pretty_print(goal, tasks)
288 return results
289
290 if match.command('remove'):
291 task_id = int(match.args()[1])
292 result = self.data.remove_task(task_id)
293 return [result]
294
295 if match.command('extra.help'):
296 return [ex_help]
297
298 # Help text
299 return [__doc__]
300
301
302