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