]> apps.delaporte.us Git - matrix-goal-bot.git/blob - matrix_goal_bot/bot.py
Update list formatting
[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
94 message_lines = []
95 for line in result_lines:
96 message_lines.append(str(line))
97
98 message = '\n'.join(message_lines)
99
100 await self.bot.api.send_text_message(
101 room.room_id, message)
102
103 except Exception as ex:
104 logger.warn(f'Caught exception: {str(ex)}')
105 dumb_msg_idx = len(str(ex)) % len(snark)
106 dumb_msg = snark[dumb_msg_idx]
107 await self.bot.api.send_text_message(
108 room.room_id, dumb_msg)
109
110 await self.bot.api.send_text_message(
111 room.room_id, str(ex))
112
113
114 async def _handle_match(self, match):
115 logger.debug(f'Try to match {str(match)}')
116
117 if match.command('setup'):
118 result = self.data.setup()
119 return [result]
120
121 if match.command('add'):
122 new = ' '.join(match.args()[1:])
123 goal_id = self.data.add_goal(new)
124 results = [f'Goal added with id {goal_id}']
125
126 goals = self.data.get_all_goals()
127 results.append('# Goals list...')
128 for goal in goals:
129 results.append(str(goal))
130
131 return results
132
133 if match.command('list'):
134 logger.debug('Asked to list current goals...')
135 goals = self.data.get_current_goals()
136 results = ['# Goals list']
137 results.append('------------']
138 for goal in goals:
139 results.append(str(goal))
140 return results
141
142
143 if match.command('list.done'):
144 goals = self.data.get_done_goals()
145 results = ['# Completed Goals...']
146 for goal in goals:
147 results.append(str(goal))
148 return results
149
150 if match.command('task'):
151 new = ' '.join(match.args()[1:])
152 goal_id = self.data.quick_add_task(new)
153 goal,tasks = self.data.get_goal(goal_id)
154 results = pretty_print(goal, tasks)
155 return results
156
157 if match.command('add.vision'):
158 new = ' '.join(match.args()[1:])
159 result = self.data.add_vision(new)
160 return [f'Vision added with id {result}']
161
162 if match.command('print'):
163 if len(match.args()) > 1:
164 goal_id = int(match.args()[1])
165 else:
166 goal_id = self.data._get_pref_goal_id()
167
168 logger.debug(f'Searching for goal {goal_id}...')
169 goal,tasks = self.data.get_goal(goal_id)
170 results = pretty_print(goal, tasks)
171
172 return results
173
174
175 if match.command('print.vision'):
176 get_id = int(match.args()[1])
177 vision,goals = self.data.get_vision(get_id)
178 results = pretty_print(vision, goals)
179 return results
180
181 if match.command('close'):
182 goal_id = int(match.args()[1])
183 vision_id = self.data.complete_goal(goal_id)
184 vision,goals = self.data.get_vision(vision_id)
185 results = pretty_print(vision, goals)
186 return results
187
188
189 if match.command('clear'):
190 if len(match.args()) > 1:
191 goal_id = int(match.args()[1])
192 else:
193 goal_id = self.data._get_pref_goal_id()
194 _ = self.data.clear(goal_id)
195
196 goal,tasks = self.data.get_goal(goal_id)
197 results = pretty_print(goal, tasks)
198 return results
199
200
201 if match.command('start'):
202 goal_id = int(match.args()[1])
203 vision,goals = self.data.start_goal(goal_id)
204 results = pretty_print(vision, goals)
205 return results
206
207 if match.command('later'):
208 vision_id = int(match.args()[1])
209 self.data.put_off_vision(vision_id)
210 # Want to see what we just cleaned up
211 goals = self.data.get_current_goals()
212 results = ['# Goals list...']
213 for goal in goals:
214 results.append(str(goal))
215 return results
216
217
218 if match.command('close.vision'):
219 vision_id = int(match.args()[1])
220 self.data.complete_vision(vision_id)
221 vision,goals = self.data.get_vision(vision_id)
222 results = pretty_print(vision, goals)
223 return results
224
225 if match.command('done'):
226 ids = match.args()[1:]
227 for task_id in ids:
228 goal_id = self.data.complete_task(int(task_id))
229 # Print the goal of the last closed task
230 goal,tasks = self.data.get_goal(goal_id)
231 results = pretty_print(goal, tasks)
232 return results
233
234 if match.command('dump'):
235 goals = self.data.get_all_goals()
236 results = ['# Everything ... ']
237 for goal in goals:
238 _,tasks = self.data.get_goal(goal.id)
239 details = pretty_print(goal, tasks)
240 results += details
241 return results
242
243
244 if match.command('list.later'):
245 goals = self.data.get_all_goals()
246 results = ['# All Goals ... ']
247 return results
248
249 if match.command('visions'):
250 items = self.data.get_all_visions()
251 results = ['# Visions']
252 if not items:
253 results.append('-- No current visions --')
254
255 for item in items:
256 results.append(item)
257 return results
258
259 if match.command('visionless'):
260 items = self.data.visionless()
261 results = ['# Goals with no vision']
262 if not items:
263 results.append('-- No visionless goals --')
264
265 for item in items:
266 results.append(item)
267 return results
268
269 if match.command('wins'):
270 items = self.data.wins()
271 results = ['# Wins']
272 if not items:
273 results.append('-- No wins yet --')
274
275 for item in items:
276 results.append(item)
277 return results
278
279
280
281 if match.command('set.vision'):
282 goal_id = int(match.args()[1])
283 vision_id = int(match.args()[2])
284 self.data.assign_vision(goal_id=goal_id, vision_id=vision_id)
285 vision,goals = self.data.get_vision(vision_id)
286 results = pretty_print(vision, goals)
287 return results
288
289
290 if match.command('rename'):
291 goal_id = int(match.args()[1])
292 name = ' '.join(match.args()[2:])
293 self.data.rename_goal(goal_id=goal_id, name=name)
294 goal,tasks = self.data.get_goal(goal_id)
295 results = pretty_print(goal, tasks)
296 return results
297
298 if match.command('remove'):
299 task_id = int(match.args()[1])
300 result = self.data.remove_task(task_id)
301 return [result]
302
303 if match.command('extra.help'):
304 return [ex_help]
305
306 # Help text
307 return [__doc__]
308
309
310