]> us-delaporte.pagekite.me Git - matrix-goal-bot.git/blob - matrix_goal_bot/bot.py
ade650a6fe154ba02033d59a525984dfd3385885
[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 for goal in goals:
138 results.append(str(goal))
139 return results
140
141
142 if match.command('list.done'):
143 goals = self.data.get_done_goals()
144 results = ['# Completed Goals...']
145 for goal in goals:
146 results.append(str(goal))
147 return results
148
149 if match.command('task'):
150 new = ' '.join(match.args()[1:])
151 goal_id = self.data.quick_add_task(new)
152 goal,tasks = self.data.get_goal(goal_id)
153 results = pretty_print(goal, tasks)
154 return results
155
156 if match.command('add.vision'):
157 new = ' '.join(match.args()[1:])
158 result = self.data.add_vision(new)
159 return [f'Vision added with id {result}']
160
161 if match.command('print'):
162 if len(match.args()) > 1:
163 goal_id = int(match.args()[1])
164 else:
165 goal_id = self.data._get_pref_goal_id()
166
167 logger.debug(f'Searching for goal {goal_id}...')
168 goal,tasks = self.data.get_goal(goal_id)
169 results = pretty_print(goal, tasks)
170
171 return results
172
173
174 if match.command('print.vision'):
175 get_id = int(match.args()[1])
176 vision,goals = self.data.get_vision(get_id)
177 results = pretty_print(vision, goals)
178 return results
179
180 if match.command('close'):
181 goal_id = int(match.args()[1])
182 vision_id = self.data.complete_goal(goal_id)
183 vision,goals = self.data.get_vision(vision_id)
184 results = pretty_print(vision, goals)
185 return results
186
187
188 if match.command('clear'):
189 if len(match.args()) > 1:
190 goal_id = int(match.args()[1])
191 else:
192 goal_id = self.data._get_pref_goal_id()
193 _ = self.data.clear(goal_id)
194
195 goal,tasks = self.data.get_goal(goal_id)
196 results = pretty_print(goal, tasks)
197 return results
198
199
200 if match.command('start'):
201 goal_id = int(match.args()[1])
202 vision,goals = self.data.start_goal(goal_id)
203 results = pretty_print(vision, goals)
204 return results
205
206 if match.command('later'):
207 vision_id = int(match.args()[1])
208 self.data.put_off_vision(vision_id)
209 # Want to see what we just cleaned up
210 goals = self.data.get_current_goals()
211 results = ['# Goals list...']
212 for goal in goals:
213 results.append(str(goal))
214 return results
215
216
217 if match.command('close.vision'):
218 vision_id = int(match.args()[1])
219 self.data.complete_vision(vision_id)
220 vision,goals = self.data.get_vision(vision_id)
221 results = pretty_print(vision, goals)
222 return results
223
224 if match.command('done'):
225 ids = match.args()[1:]
226 for task_id in ids:
227 goal_id = self.data.complete_task(int(task_id))
228 # Print the goal of the last closed task
229 goal,tasks = self.data.get_goal(goal_id)
230 results = pretty_print(goal, tasks)
231 return results
232
233 if match.command('dump'):
234 goals = self.data.get_all_goals()
235 results = ['# Everything ... ']
236 for goal in goals:
237 _,tasks = self.data.get_goal(goal.id)
238 details = pretty_print(goal, tasks)
239 results += details
240 return results
241
242
243 if match.command('list.later'):
244 goals = self.data.get_all_goals()
245 results = ['# All Goals ... ']
246 return results
247
248 if match.command('visions'):
249 items = self.data.get_all_visions()
250 results = ['# Visions']
251 if not items:
252 results.append('-- No current visions --')
253
254 for item in items:
255 results.append(item)
256 return results
257
258 if match.command('visionless'):
259 items = self.data.visionless()
260 results = ['# Goals with no vision']
261 if not items:
262 results.append('-- No visionless goals --')
263
264 for item in items:
265 results.append(item)
266 return results
267
268 if match.command('wins'):
269 items = self.data.wins()
270 results = ['# Wins']
271 if not items:
272 results.append('-- No wins yet --')
273
274 for item in items:
275 results.append(item)
276 return results
277
278
279
280 if match.command('set.vision'):
281 goal_id = int(match.args()[1])
282 vision_id = int(match.args()[2])
283 self.data.assign_vision(goal_id=goal_id, vision_id=vision_id)
284 vision,goals = self.data.get_vision(vision_id)
285 results = pretty_print(vision, goals)
286 return results
287
288
289 if match.command('rename'):
290 goal_id = int(match.args()[1])
291 name = ' '.join(match.args()[2:])
292 self.data.rename_goal(goal_id=goal_id, name=name)
293 goal,tasks = self.data.get_goal(goal_id)
294 results = pretty_print(goal, tasks)
295 return results
296
297 if match.command('remove'):
298 task_id = int(match.args()[1])
299 result = self.data.remove_task(task_id)
300 return [result]
301
302 if match.command('extra.help'):
303 return [ex_help]
304
305 # Help text
306 return [__doc__]
307
308
309