Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_text_commands.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | ae5f63e5ed2c |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
64 | 64 |
65 def __init__(self, host): | 65 def __init__(self, host): |
66 log.info(_("Text commands initialization")) | 66 log.info(_("Text commands initialization")) |
67 self.host = host | 67 self.host = host |
68 # this is internal command, so we set high priority | 68 # this is internal command, so we set high priority |
69 host.trigger.add("sendMessage", self.sendMessageTrigger, priority=1000000) | 69 host.trigger.add("sendMessage", self.send_message_trigger, priority=1000000) |
70 self._commands = {} | 70 self._commands = {} |
71 self._whois = [] | 71 self._whois = [] |
72 self.registerTextCommands(self) | 72 self.register_text_commands(self) |
73 | 73 |
74 def _parseDocString(self, cmd, cmd_name): | 74 def _parse_doc_string(self, cmd, cmd_name): |
75 """Parse a docstring to get text command data | 75 """Parse a docstring to get text command data |
76 | 76 |
77 @param cmd: function or method callback for the command, | 77 @param cmd: function or method callback for the command, |
78 its docstring will be used for self documentation in the following way: | 78 its docstring will be used for self documentation in the following way: |
79 - first line is the command short documentation, shown with /help | 79 - first line is the command short documentation, shown with /help |
148 ) | 148 ) |
149 ) | 149 ) |
150 | 150 |
151 return data | 151 return data |
152 | 152 |
153 def registerTextCommands(self, instance): | 153 def register_text_commands(self, instance): |
154 """ Add a text command | 154 """ Add a text command |
155 | 155 |
156 @param instance: instance of a class containing text commands | 156 @param instance: instance of a class containing text commands |
157 """ | 157 """ |
158 for attr in dir(instance): | 158 for attr in dir(instance): |
174 "Conflict for command [{old_name}], renaming it to [{new_name}]" | 174 "Conflict for command [{old_name}], renaming it to [{new_name}]" |
175 ).format(old_name=cmd_name, new_name=new_name) | 175 ).format(old_name=cmd_name, new_name=new_name) |
176 ) | 176 ) |
177 cmd_name = new_name | 177 cmd_name = new_name |
178 self._commands[cmd_name] = cmd_data = {"callback": cmd} | 178 self._commands[cmd_name] = cmd_data = {"callback": cmd} |
179 cmd_data.update(self._parseDocString(cmd, cmd_name)) | 179 cmd_data.update(self._parse_doc_string(cmd, cmd_name)) |
180 log.info(_("Registered text command [%s]") % cmd_name) | 180 log.info(_("Registered text command [%s]") % cmd_name) |
181 | 181 |
182 def addWhoIsCb(self, callback, priority=0): | 182 def add_who_is_cb(self, callback, priority=0): |
183 """Add a callback which give information to the /whois command | 183 """Add a callback which give information to the /whois command |
184 | 184 |
185 @param callback: a callback which will be called with the following arguments | 185 @param callback: a callback which will be called with the following arguments |
186 - whois_msg: list of information strings to display, callback need to append | 186 - whois_msg: list of information strings to display, callback need to append |
187 its own strings to it | 187 its own strings to it |
191 be displayed first) | 191 be displayed first) |
192 """ | 192 """ |
193 self._whois.append((priority, callback)) | 193 self._whois.append((priority, callback)) |
194 self._whois.sort(key=lambda item: item[0], reverse=True) | 194 self._whois.sort(key=lambda item: item[0], reverse=True) |
195 | 195 |
196 def sendMessageTrigger( | 196 def send_message_trigger( |
197 self, client, mess_data, pre_xml_treatments, post_xml_treatments | 197 self, client, mess_data, pre_xml_treatments, post_xml_treatments |
198 ): | 198 ): |
199 """Install SendMessage command hook """ | 199 """Install SendMessage command hook """ |
200 pre_xml_treatments.addCallback(self._sendMessageCmdHook, client) | 200 pre_xml_treatments.addCallback(self._send_message_cmd_hook, client) |
201 return True | 201 return True |
202 | 202 |
203 def _sendMessageCmdHook(self, mess_data, client): | 203 def _send_message_cmd_hook(self, mess_data, client): |
204 """ Check text commands in message, and react consequently | 204 """ Check text commands in message, and react consequently |
205 | 205 |
206 msg starting with / are potential command. If a command is found, it is executed, | 206 msg starting with / are potential command. If a command is found, it is executed, |
207 else an help message is sent. | 207 else an help message is sent. |
208 msg starting with // are escaped: they are sent with a single / | 208 msg starting with // are escaped: they are sent with a single / |
237 | 237 |
238 # we have a command | 238 # we have a command |
239 d = None | 239 d = None |
240 command = msg[1:].partition(" ")[0].lower().strip() | 240 command = msg[1:].partition(" ")[0].lower().strip() |
241 if not command.isidentifier(): | 241 if not command.isidentifier(): |
242 self.feedBack( | 242 self.feed_back( |
243 client, | 243 client, |
244 _("Invalid command /%s. ") % command + self.HELP_SUGGESTION, | 244 _("Invalid command /%s. ") % command + self.HELP_SUGGESTION, |
245 mess_data, | 245 mess_data, |
246 ) | 246 ) |
247 raise failure.Failure(exceptions.CancelError()) | 247 raise failure.Failure(exceptions.CancelError()) |
248 | 248 |
249 # looks like an actual command, we try to call the corresponding method | 249 # looks like an actual command, we try to call the corresponding method |
250 def retHandling(ret): | 250 def ret_handling(ret): |
251 """ Handle command return value: | 251 """ Handle command return value: |
252 if ret is True, normally send message (possibly modified by command) | 252 if ret is True, normally send message (possibly modified by command) |
253 else, abord message sending | 253 else, abord message sending |
254 """ | 254 """ |
255 if ret: | 255 if ret: |
256 return mess_data | 256 return mess_data |
257 else: | 257 else: |
258 log.debug("text command detected ({})".format(command)) | 258 log.debug("text command detected ({})".format(command)) |
259 raise failure.Failure(exceptions.CancelError()) | 259 raise failure.Failure(exceptions.CancelError()) |
260 | 260 |
261 def genericErrback(failure): | 261 def generic_errback(failure): |
262 try: | 262 try: |
263 msg = "with condition {}".format(failure.value.condition) | 263 msg = "with condition {}".format(failure.value.condition) |
264 except AttributeError: | 264 except AttributeError: |
265 msg = "with error {}".format(failure.value) | 265 msg = "with error {}".format(failure.value) |
266 self.feedBack(client, "Command failed {}".format(msg), mess_data) | 266 self.feed_back(client, "Command failed {}".format(msg), mess_data) |
267 return False | 267 return False |
268 | 268 |
269 mess_data["unparsed"] = msg[ | 269 mess_data["unparsed"] = msg[ |
270 1 + len(command) : | 270 1 + len(command) : |
271 ] # part not yet parsed of the message | 271 ] # part not yet parsed of the message |
272 try: | 272 try: |
273 cmd_data = self._commands[command] | 273 cmd_data = self._commands[command] |
274 except KeyError: | 274 except KeyError: |
275 self.feedBack( | 275 self.feed_back( |
276 client, | 276 client, |
277 _("Unknown command /%s. ") % command + self.HELP_SUGGESTION, | 277 _("Unknown command /%s. ") % command + self.HELP_SUGGESTION, |
278 mess_data, | 278 mess_data, |
279 ) | 279 ) |
280 log.debug("text command help message") | 280 log.debug("text command help message") |
281 raise failure.Failure(exceptions.CancelError()) | 281 raise failure.Failure(exceptions.CancelError()) |
282 else: | 282 else: |
283 if not self._contextValid(mess_data, cmd_data): | 283 if not self._context_valid(mess_data, cmd_data): |
284 # The command is not launched in the right context, we throw a message with help instructions | 284 # The command is not launched in the right context, we throw a message with help instructions |
285 context_txt = ( | 285 context_txt = ( |
286 _("group discussions") | 286 _("group discussions") |
287 if cmd_data["type"] == "group" | 287 if cmd_data["type"] == "group" |
288 else _("one to one discussions") | 288 else _("one to one discussions") |
289 ) | 289 ) |
290 feedback = _("/{command} command only applies in {context}.").format( | 290 feedback = _("/{command} command only applies in {context}.").format( |
291 command=command, context=context_txt | 291 command=command, context=context_txt |
292 ) | 292 ) |
293 self.feedBack( | 293 self.feed_back( |
294 client, "{} {}".format(feedback, self.HELP_SUGGESTION), mess_data | 294 client, "{} {}".format(feedback, self.HELP_SUGGESTION), mess_data |
295 ) | 295 ) |
296 log.debug("text command invalid message") | 296 log.debug("text command invalid message") |
297 raise failure.Failure(exceptions.CancelError()) | 297 raise failure.Failure(exceptions.CancelError()) |
298 else: | 298 else: |
299 d = utils.asDeferred(cmd_data["callback"], client, mess_data) | 299 d = utils.as_deferred(cmd_data["callback"], client, mess_data) |
300 d.addErrback(genericErrback) | 300 d.addErrback(generic_errback) |
301 d.addCallback(retHandling) | 301 d.addCallback(ret_handling) |
302 | 302 |
303 return d | 303 return d |
304 | 304 |
305 def _contextValid(self, mess_data, cmd_data): | 305 def _context_valid(self, mess_data, cmd_data): |
306 """Tell if a command can be used in the given context | 306 """Tell if a command can be used in the given context |
307 | 307 |
308 @param mess_data(dict): message data as given in sendMessage trigger | 308 @param mess_data(dict): message data as given in sendMessage trigger |
309 @param cmd_data(dict): command data as returned by self._parseDocString | 309 @param cmd_data(dict): command data as returned by self._parse_doc_string |
310 @return (bool): True if command can be used in this context | 310 @return (bool): True if command can be used in this context |
311 """ | 311 """ |
312 if (cmd_data["type"] == "group" and mess_data["type"] != "groupchat") or ( | 312 if (cmd_data["type"] == "group" and mess_data["type"] != "groupchat") or ( |
313 cmd_data["type"] == "one2one" and mess_data["type"] == "groupchat" | 313 cmd_data["type"] == "one2one" and mess_data["type"] == "groupchat" |
314 ): | 314 ): |
315 return False | 315 return False |
316 return True | 316 return True |
317 | 317 |
318 def getRoomJID(self, arg, service_jid): | 318 def get_room_jid(self, arg, service_jid): |
319 """Return a room jid with a shortcut | 319 """Return a room jid with a shortcut |
320 | 320 |
321 @param arg: argument: can be a full room jid (e.g.: sat@chat.jabberfr.org) | 321 @param arg: argument: can be a full room jid (e.g.: sat@chat.jabberfr.org) |
322 or a shortcut (e.g.: sat or sat@ for sat on current service) | 322 or a shortcut (e.g.: sat or sat@ for sat on current service) |
323 @param service_jid: jid of the current service (e.g.: chat.jabberfr.org) | 323 @param service_jid: jid of the current service (e.g.: chat.jabberfr.org) |
327 if arg[-1] != "@": | 327 if arg[-1] != "@": |
328 return jid.JID(arg) | 328 return jid.JID(arg) |
329 return jid.JID(arg + service_jid) | 329 return jid.JID(arg + service_jid) |
330 return jid.JID(f"{arg}@{service_jid}") | 330 return jid.JID(f"{arg}@{service_jid}") |
331 | 331 |
332 def feedBack(self, client, message, mess_data, info_type=FEEDBACK_INFO_TYPE): | 332 def feed_back(self, client, message, mess_data, info_type=FEEDBACK_INFO_TYPE): |
333 """Give a message back to the user""" | 333 """Give a message back to the user""" |
334 if mess_data["type"] == "groupchat": | 334 if mess_data["type"] == "groupchat": |
335 to_ = mess_data["to"].userhostJID() | 335 to_ = mess_data["to"].userhostJID() |
336 else: | 336 else: |
337 to_ = client.jid | 337 to_ = client.jid |
340 mess_data["from"] = mess_data["to"] | 340 mess_data["from"] = mess_data["to"] |
341 mess_data["to"] = to_ | 341 mess_data["to"] = to_ |
342 mess_data["type"] = C.MESS_TYPE_INFO | 342 mess_data["type"] = C.MESS_TYPE_INFO |
343 mess_data["message"] = {"": message} | 343 mess_data["message"] = {"": message} |
344 mess_data["extra"]["info_type"] = info_type | 344 mess_data["extra"]["info_type"] = info_type |
345 client.messageSendToBridge(mess_data) | 345 client.message_send_to_bridge(mess_data) |
346 | 346 |
347 def cmd_whois(self, client, mess_data): | 347 def cmd_whois(self, client, mess_data): |
348 """show informations on entity | 348 """show informations on entity |
349 | 349 |
350 @command: [JID|ROOM_NICK] | 350 @command: [JID|ROOM_NICK] |
356 entity = mess_data["unparsed"].strip() | 356 entity = mess_data["unparsed"].strip() |
357 | 357 |
358 if mess_data["type"] == "groupchat": | 358 if mess_data["type"] == "groupchat": |
359 room = mess_data["to"].userhostJID() | 359 room = mess_data["to"].userhostJID() |
360 try: | 360 try: |
361 if self.host.plugins["XEP-0045"].isNickInRoom(client, room, entity): | 361 if self.host.plugins["XEP-0045"].is_nick_in_room(client, room, entity): |
362 entity = "%s/%s" % (room, entity) | 362 entity = "%s/%s" % (room, entity) |
363 except KeyError: | 363 except KeyError: |
364 log.warning("plugin XEP-0045 is not present") | 364 log.warning("plugin XEP-0045 is not present") |
365 | 365 |
366 if not entity: | 366 if not entity: |
369 try: | 369 try: |
370 target_jid = jid.JID(entity) | 370 target_jid = jid.JID(entity) |
371 if not target_jid.user or not target_jid.host: | 371 if not target_jid.user or not target_jid.host: |
372 raise jid.InvalidFormat | 372 raise jid.InvalidFormat |
373 except (RuntimeError, jid.InvalidFormat, AttributeError): | 373 except (RuntimeError, jid.InvalidFormat, AttributeError): |
374 self.feedBack(client, _("Invalid jid, can't whois"), mess_data) | 374 self.feed_back(client, _("Invalid jid, can't whois"), mess_data) |
375 return False | 375 return False |
376 | 376 |
377 if not target_jid.resource: | 377 if not target_jid.resource: |
378 target_jid.resource = self.host.memory.getMainResource(client, target_jid) | 378 target_jid.resource = self.host.memory.main_resource_get(client, target_jid) |
379 | 379 |
380 whois_msg = [_("whois for %(jid)s") % {"jid": target_jid}] | 380 whois_msg = [_("whois for %(jid)s") % {"jid": target_jid}] |
381 | 381 |
382 d = defer.succeed(None) | 382 d = defer.succeed(None) |
383 for __, callback in self._whois: | 383 for __, callback in self._whois: |
384 d.addCallback( | 384 d.addCallback( |
385 lambda __: callback(client, whois_msg, mess_data, target_jid) | 385 lambda __: callback(client, whois_msg, mess_data, target_jid) |
386 ) | 386 ) |
387 | 387 |
388 def feedBack(__): | 388 def feed_back(__): |
389 self.feedBack(client, "\n".join(whois_msg), mess_data) | 389 self.feed_back(client, "\n".join(whois_msg), mess_data) |
390 return False | 390 return False |
391 | 391 |
392 d.addCallback(feedBack) | 392 d.addCallback(feed_back) |
393 return d | 393 return d |
394 | 394 |
395 def _getArgsHelp(self, cmd_data): | 395 def _get_args_help(self, cmd_data): |
396 """Return help string for args of cmd_name, according to docstring data | 396 """Return help string for args of cmd_name, according to docstring data |
397 | 397 |
398 @param cmd_data: command data | 398 @param cmd_data: command data |
399 @return (list[unicode]): help strings | 399 @return (list[unicode]): help strings |
400 """ | 400 """ |
418 # We just ignore the command as the match is done on receiption by clients | 418 # We just ignore the command as the match is done on receiption by clients |
419 return True | 419 return True |
420 | 420 |
421 def cmd_whoami(self, client, mess_data): | 421 def cmd_whoami(self, client, mess_data): |
422 """give your own jid""" | 422 """give your own jid""" |
423 self.feedBack(client, client.jid.full(), mess_data) | 423 self.feed_back(client, client.jid.full(), mess_data) |
424 | 424 |
425 def cmd_help(self, client, mess_data): | 425 def cmd_help(self, client, mess_data): |
426 """show help on available commands | 426 """show help on available commands |
427 | 427 |
428 @command: [cmd_name] | 428 @command: [cmd_name] |
430 """ | 430 """ |
431 cmd_name = mess_data["unparsed"].strip() | 431 cmd_name = mess_data["unparsed"].strip() |
432 if cmd_name and cmd_name[0] == "/": | 432 if cmd_name and cmd_name[0] == "/": |
433 cmd_name = cmd_name[1:] | 433 cmd_name = cmd_name[1:] |
434 if cmd_name and cmd_name not in self._commands: | 434 if cmd_name and cmd_name not in self._commands: |
435 self.feedBack( | 435 self.feed_back( |
436 client, _("Invalid command name [{}]\n".format(cmd_name)), mess_data | 436 client, _("Invalid command name [{}]\n".format(cmd_name)), mess_data |
437 ) | 437 ) |
438 cmd_name = "" | 438 cmd_name = "" |
439 if not cmd_name: | 439 if not cmd_name: |
440 # we show the global help | 440 # we show the global help |
441 longuest = max([len(command) for command in self._commands]) | 441 longuest = max([len(command) for command in self._commands]) |
442 help_cmds = [] | 442 help_cmds = [] |
443 | 443 |
444 for command in sorted(self._commands): | 444 for command in sorted(self._commands): |
445 cmd_data = self._commands[command] | 445 cmd_data = self._commands[command] |
446 if not self._contextValid(mess_data, cmd_data): | 446 if not self._context_valid(mess_data, cmd_data): |
447 continue | 447 continue |
448 spaces = (longuest - len(command)) * " " | 448 spaces = (longuest - len(command)) * " " |
449 help_cmds.append( | 449 help_cmds.append( |
450 " /{command}: {spaces} {short_help}".format( | 450 " /{command}: {spaces} {short_help}".format( |
451 command=command, | 451 command=command, |
462 help_mess = _("/{name}: {short_help}\n{syntax}{args_help}").format( | 462 help_mess = _("/{name}: {short_help}\n{syntax}{args_help}").format( |
463 name=cmd_name, | 463 name=cmd_name, |
464 short_help=cmd_data["doc_short_help"], | 464 short_help=cmd_data["doc_short_help"], |
465 syntax=_(" " * 4 + "syntax: {}\n").format(syntax) if syntax else "", | 465 syntax=_(" " * 4 + "syntax: {}\n").format(syntax) if syntax else "", |
466 args_help="\n".join( | 466 args_help="\n".join( |
467 [" " * 8 + "{}".format(line) for line in self._getArgsHelp(cmd_data)] | 467 [" " * 8 + "{}".format(line) for line in self._get_args_help(cmd_data)] |
468 ), | 468 ), |
469 ) | 469 ) |
470 | 470 |
471 self.feedBack(client, help_mess, mess_data) | 471 self.feed_back(client, help_mess, mess_data) |