]> git.somenet.org - pub/jan/mattermost-bot.git/blob - core/AbstractCommand.py
modules/DialogManagedCourseFeedback.py
[pub/jan/mattermost-bot.git] / core / AbstractCommand.py
1 # Mattermost Bot.
2 #  Copyright (c) 2016-2022 by Someone <someone@somenet.org> (aka. Jan Vales <jan@jvales.net>)
3 #  published under MIT-License
4
5
6 class RequireException(Exception):
7     """Required precondition not met-exception. Mostly used for permission checks. Message will be forwarded to command-caller/user"""
8
9
10 class AbstractCommand():
11     ICON_PUBLIC = "📢 "
12     ICON_DM = "👥 "
13     ICON_PRIVATE = "🥷 "
14
15     URL = None
16     TEAM_ID = None
17     TRIGGER = None
18     CONFIG = {"display_name": "somebot-command", "auto_complete": True}
19     USEINFO = None
20
21     bot = None
22     mm_secret_token = None
23
24
25     def __init__(self, team_id):
26         self.TEAM_ID = team_id
27
28     def __str__(self):
29         return str(self.__class__)+" for team_id: "+str(self.TEAM_ID)
30
31     def __repr__(self):
32         return self.__str__()
33
34
35     # can/should be overridden by the user
36     def on_register(self):
37         """Consider to override. Handles the post-command-registration logic at bot startup."""
38         self._create_slash_command()
39
40     # can/should be overridden by the user
41     def on_shutdown(self):
42         """Consider to override. Handles the shutdown-procedure."""
43         return
44
45     # can/should be overridden by the user
46     def on_SIGUSR1(self, sigusr1_cnt):
47         """Consider to override. Handles the SIGUSR1-signal."""
48         return
49
50     # should be overridden by the user
51     def on_POST(self, request, data):
52         """Override. Handles the post-command logic."""
53         return
54
55     # should be overridden by the user
56     # manual command authentication needed!
57     def on_POST_interactive(self, request, data):
58         """Consider to override. Handles the interactive-message logic."""
59         return
60
61     # should be overridden by the user
62     # manual command authentication needed!
63     def on_POST_dialog(self, request, data):
64         """Consider to override. Handles the dialog logic."""
65         return
66
67
68     def _on_register(self, bot):
69         self.bot = bot
70         self.URL = self.bot.local_websrv_url+"/"+self.TEAM_ID+"/"+self.TRIGGER
71         if self.USEINFO:
72             self.bot.USETOPICS.setdefault("/"+self.TRIGGER, self.USEINFO)
73         self.on_register()
74
75
76     def _on_shutdown(self):
77         self.on_shutdown()
78
79
80     def _on_SIGUSR1(self, sigusr1_cnt):
81         self.on_SIGUSR1(sigusr1_cnt)
82
83
84     def _on_POST(self, request, data):
85         try:
86             self._require_not_guest(data)
87             self.on_POST(request, data)
88         except RequireException as ex:
89             request.respond_cmd_err(str(ex))
90
91
92     def _on_POST_interactive(self, request, data):
93         try:
94             self._require_not_guest(data)
95             self.on_POST_interactive(request, data)
96         except RequireException as ex:
97             request.respond_cmd_err(str(ex))
98
99
100     def _on_POST_dialog(self, request, data):
101         try:
102             self._require_not_guest(data)
103             self.on_POST_dialog(request, data)
104         except RequireException as ex:
105             request.respond_cmd_err(str(ex))
106
107
108     def _create_slash_command(self):
109         # (possibly) delete old version of command
110         for command in self.bot.api.list_custom_slash_commands_for_team(self.TEAM_ID):
111             if command["url"] == self.URL or command["trigger"].lower() == self.TRIGGER.lower():
112                 self.bot.api.delete_slash_command(command["id"])
113
114         # create slash command
115         res = self.bot.api.create_slash_command(self.TEAM_ID, self.TRIGGER.lower(), self.URL+"/command")
116         res.update(self.CONFIG)
117         self.bot.api.update_slash_command(res)
118         self.mm_secret_token = res["token"]
119
120
121     def _require_bot_admin(self, data):
122         """
123         Require exactly bot admin priviledges.
124         Throws RequireException if not priviledged.
125         """
126         if not data["user_id"] in self.bot.admin_ids:
127             raise RequireException("### Leave me alone. You are not by real dad.")
128
129
130     def _require_system_admin(self, data, exc=True):
131         """
132         Require at least team admin priviledges.
133         Throws RequireException if not priviledged.
134         """
135         user = self.bot.api.get_user(data["user_id"])
136         if "system_admin" not in user["roles"]:
137             if exc:
138                 raise RequireException("### You are not SYSTEM_ADMIN. :(")
139             return False
140         return True
141
142
143     def _require_team_admin(self, data, exc=True):
144         """
145         Require at least team admin priviledges.
146         Throws RequireException if not priviledged.
147         """
148         team_member = self.bot.api.get_team_member(data["team_id"], data["user_id"])
149         if "team_admin" not in team_member["roles"] and not self._require_system_admin(data, exc=False):
150             if exc:
151                 raise RequireException("### You are not TEAM_ADMIN. :(")
152             return False
153         return True
154
155
156     def _require_channel_admin(self, data, exc=True):
157         """
158         Require at least channel admin priviledges.
159         Throws RequireException if not priviledged.
160         """
161         channel_member = self.bot.api.get_channel_member(data["channel_id"], data["user_id"])
162         if "channel_admin" not in channel_member["roles"] and not self._require_team_admin(data, exc=False):
163             if exc:
164                 raise RequireException("### You are not CHANNEL_ADMIN. :(")
165             return False
166         return True
167
168
169     def _require_not_guest(self, data, exc=True):
170         """
171         Require to not be a guest.
172         Throws RequireException if guest.
173         """
174         channel_member = self.bot.api.get_channel_member(data["channel_id"], data["user_id"])
175         if "channel_guest" in channel_member["roles"]:
176             if exc:
177                 raise RequireException("### The bot cannot be used by guests. :(")
178             return False
179         return True