diff --git a/slackbot/base.py b/slackbot/base.py index 2c6a72f..6481ee0 100644 --- a/slackbot/base.py +++ b/slackbot/base.py @@ -70,6 +70,24 @@ def handle(self, message, user=None, channel=None, ts=None, raw=None) -> Optiona """ raise NotImplementedError("abstract method") + def process_file( + self, files, message, user=None, channel=None, ts=None, raw=None + ) -> Optional[Union[int, tuple[int, int]]]: + """ + Handle file share events. Override this method to process file uploads. + + :param files: List of file objects from Slack + :param message: Optional text message accompanying the files + :param user: User ID who uploaded the files + :param channel: Channel where files were uploaded + :param ts: Timestamp of the event + :param raw: Raw event data from Slack + + :return: None, self.STOP, self.PROCESSED, or tuple PROCESSED,STOP + """ + # Default implementation falls back to regular message processing + return self.handle(message, user=user, channel=channel, ts=ts, raw=raw) + class NoMatchSlackCommand(Exception): pass diff --git a/slackbot/management/commands/run_bot.py b/slackbot/management/commands/run_bot.py index c0d569a..54373fa 100644 --- a/slackbot/management/commands/run_bot.py +++ b/slackbot/management/commands/run_bot.py @@ -118,6 +118,61 @@ def handle_message_really(self, **payload): return processed_at_least_one + def handle_file_share(self, **payload): + """ + Handle file share events (when users upload files) + """ + event = payload.get("event") + + channel = event.get("channel") + user = event.get("user") + ts = event.get("event_ts", event.get("ts", "")) + + if not channel: + return False + + # Don't process bot's own file uploads + if user == self.my_id: + return False + + # Get file information + files = event.get("files", []) + message = event.get("text", "") + + # Log the file share event + self.stdout.write(f"File share event: User {user} uploaded {len(files)} file(s) in channel {channel}") + if message: + self.stdout.write(f"Message: {message}") + + # Process files through processors + processed_at_least_one = False + for p in self.processors: + try: + # Call a new method for file processing if it exists + if hasattr(p, "process_file"): + r = p.process_file(files, message, user=user, channel=channel, ts=ts, raw=event) + if r: + if not isinstance(r, tuple): + r = (r,) + if MessageProcessor.PROCESSED in r: + processed_at_least_one = True + if MessageProcessor.STOP in r: + break + else: + # Fallback to regular message processing for backward compatibility + r = p.process(message, user=user, channel=channel, ts=ts, raw=event) + if r: + if not isinstance(r, tuple): + r = (r,) + if MessageProcessor.PROCESSED in r: + processed_at_least_one = True + if MessageProcessor.STOP in r: + break + except Exception as e: + self.log_exception("Processor failed for file share event: %s %s", files, str(e)) + + return processed_at_least_one + def set_up(self, **payload): data = self.web.auth_test() self.my_id = data.get("user_id") @@ -137,8 +192,10 @@ def process(self, client: SocketModeClient, req: SocketModeRequest): event = req.payload["event"] - if event["type"] == "message" and (event.get("subtype") is None or event.get("subtype") == "file_share") : + if event["type"] == "message" and (event.get("subtype") is None or event.get("subtype") == "file_share"): return self.handle_message(**req.payload) + elif event["type"] == "message" and event.get("subtype") == "file_share": + return self.handle_file_share(**req.payload) def process_reaction(self, client: SocketModeClient, req: SocketModeRequest): if req.type == "events_api": diff --git a/testapp/testapp/slack.py b/testapp/testapp/slack.py index 3d8a35e..7b8e0e0 100644 --- a/testapp/testapp/slack.py +++ b/testapp/testapp/slack.py @@ -35,3 +35,16 @@ def handle(self, message, user=None, channel=None, ts=None, raw=None): else: self.post_message(channel=channel, text=f'Nothing for you to see :no_entry:', thread_ts=ts) return self.PROCESSED + + def process_file(self, files, message, user=None, channel=None, ts=None, raw=None): + """ + Handle file uploads - this will now be called when users upload files! + """ + + # You can now process the files here + for file_info in files: + file_name = file_info.get('name', 'Unknown') + file_type = file_info.get('mimetype', 'Unknown') + file_size = file_info.get('size', 0) + + return self.PROCESSED