2 # Copyright (c) 2016-2022 by Someone <someone@somenet.org> (aka. Jan Vales <jan@jvales.net>)
3 # published under MIT-License
8 class RequireException(Exception):
9 """Required precondition not met-exception. Mostly used for permission checks. Message will be forwarded to command-caller/user"""
12 class AbstractCommand():
15 ICON_PRIVATE = "🥷 "
20 CONFIG = {"display_name": "somebot-command", "auto_complete": True}
24 mm_secret_token = None
27 def __init__(self, team_id):
28 self.TEAM_ID = team_id
31 return str(self.__class__)+" for team_id: "+str(self.TEAM_ID)
37 # can/should be overridden by the user
38 def on_register(self):
39 """Consider to override. Handles the post-command-registration logic at bot startup."""
40 self._create_slash_command()
42 # can/should be overridden by the user
43 def on_shutdown(self):
44 """Consider to override. Handles the shutdown-procedure."""
47 # can/should be overridden by the user
48 def on_SIGUSR1(self, sigusr1_cnt):
49 """Consider to override. Handles the SIGUSR1-signal."""
52 # should be overridden by the user
53 def on_POST(self, request, data):
54 """Override. Handles the post-command logic."""
57 # should be overridden by the user
58 # manual command authentication needed!
59 def on_POST_interactive(self, request, data):
60 """Consider to override. Handles the interactive-message logic."""
63 # should be overridden by the user
64 # manual command authentication needed!
65 def on_POST_dialog(self, request, data):
66 """Consider to override. Handles the dialog logic."""
70 def _on_register(self, bot):
72 self.URL = ("http://"+self.bot.local_websrv_hostname+":"+str(self.bot.local_websrv_port)+"/").strip("/")+"/"+self.TEAM_ID+"/"+self.TRIGGER
74 self.bot.USETOPICS.setdefault("/"+self.TRIGGER, self.USEINFO)
78 def _on_shutdown(self):
82 def _on_SIGUSR1(self, sigusr1_cnt):
83 self.on_SIGUSR1(sigusr1_cnt)
86 def _on_POST(self, request, data):
88 self._require_not_guest(data)
89 self.on_POST(request, data)
90 except RequireException as ex:
91 request.respond_cmd_err(str(ex))
94 def _on_POST_interactive(self, request, data):
96 self._require_not_guest(data)
97 self.on_POST_interactive(request, data)
98 except RequireException as ex:
99 request.respond_cmd_err(str(ex))
102 def _on_POST_dialog(self, request, data):
104 self._require_not_guest(data)
105 self.on_POST_dialog(request, data)
106 except RequireException as ex:
107 request.respond_cmd_err(str(ex))
110 def _create_slash_command(self):
111 # (possibly) delete old version of command
112 for command in self.bot.api.list_custom_slash_commands_for_team(self.TEAM_ID):
113 if command["url"] == self.URL or command["trigger"].lower() == self.TRIGGER.lower():
114 self.bot.api.delete_slash_command(command["id"])
116 # create slash command
117 res = self.bot.api.create_slash_command(self.TEAM_ID, self.TRIGGER.lower(), self.URL+"/command")
118 res.update(self.CONFIG)
119 self.bot.api.update_slash_command(res)
120 self.mm_secret_token = res["token"]
123 def _require_bot_admin(self, data):
125 Require exactly bot admin priviledges.
126 Throws RequireException if not priviledged.
128 if not data["user_id"] in self.bot.admin_ids:
129 raise RequireException("### Leave me alone. You are not by real dad.")
132 def _require_system_admin(self, data, exc=True):
134 Require at least team admin priviledges.
135 Throws RequireException if not priviledged.
137 user = self.bot.api.get_user(data["user_id"])
138 if "system_admin" not in user["roles"]:
140 raise RequireException("### You are not SYSTEM_ADMIN. :(")
145 def _require_team_admin(self, data, exc=True):
147 Require at least team admin priviledges.
148 Throws RequireException if not priviledged.
150 team_member = self.bot.api.get_team_member(data["team_id"], data["user_id"])
151 if "team_admin" not in team_member["roles"] and not self._require_system_admin(data, exc=False):
153 raise RequireException("### You are not TEAM_ADMIN. :(")
158 def _require_channel_admin(self, data, exc=True):
160 Require at least channel admin priviledges.
161 Throws RequireException if not priviledged.
163 channel_member = self.bot.api.get_channel_member(data["channel_id"], data["user_id"])
164 if "channel_admin" not in channel_member["roles"] and not self._require_team_admin(data, exc=False):
166 raise RequireException("### You are not CHANNEL_ADMIN. :(")
171 def _require_not_guest(self, data, exc=True):
173 Require to not be a guest.
174 Throws RequireException if guest.
176 channel_member = self.bot.api.get_channel_member(data["channel_id"], data["user_id"])
177 if "channel_guest" in channel_member["roles"]:
179 raise RequireException("### The bot cannot be used by guests. :(")
184 def _require_in_channel(self, in_channel, data, exc=True):
186 Require to be in a channel.
187 Throws RequireException if not in the given channel.
191 channel_member = self.bot.api.get_channel_member(in_channel, data["user_id"], exc=True)
192 except mattermost.ApiException as ex:
194 raise RequireException("### You are not in the required channel :(")