def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) failed: List[str] = [] stream_tuples: Optional[List[Any]] = split( message['command'], converter = [lambda t: split( t, sep = ',', exact_split = 2, discard_empty = False )] ) if stream_tuples is None or None in stream_tuples: return Response.error(message) for stream, desc in stream_tuples: if not stream: failed.append('one empty stream name') continue result: Dict[str, Any] = self.client.add_subscriptions( streams = [{'name': stream, 'description': desc}] ) if result['result'] != 'success': failed.append(f'stream: {stream}, description: {desc}') if not failed: return Response.ok(message) response: str = 'Failed to create the following streams:\n' + '\n'.join(failed) return Response.build_message(message, response, msg_type = 'private')
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) handlers: List[logging.Handler] = logging.getLogger().handlers if not handlers or len(handlers) > 1: return Response.build_message(message, 'Cannot determine the logfile.') if not isinstance(handlers[0], logging.FileHandler): return Response.build_message(message, 'No logfile in use.') # Upload the logfile. (see https://zulip.com/api/upload-file) with open(handlers[0].baseFilename, 'rb') as lf: result: Dict[str, Any] = self.client.call_endpoint('user_uploads', method='POST', files=[lf]) if result['result'] != 'success': return Response.build_message(message, 'Could not upload the logfile.') return Response.build_message(message, '[logfile]({})'.format(result['uri']))
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: result: Optional[Tuple[str, CommandParser.Opts, CommandParser.Args]] if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) result = self.command_parser.parse(message['command']) if result is None: return Response.command_not_found(message) command, _, args = result if command == 'list': response: str = 'Key | Value\n ---- | ----' for key, value in self._db.execute(self._list_sql): response += f'\n{key} | {value}' return Response.build_message(message, response) if command == 'remove': self._db.execute(self._remove_sql, args.key, commit=True) return Response.ok(message) if command == 'set': try: self._db.execute(self._update_sql, args.key, args.value, commit=True) except Exception as e: logging.exception(e) return Response.build_message(message, 'Failed: %s' % str(e)) return Response.ok(message) return Response.command_not_found(message)
def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: result: Optional[Tuple[str, CommandParser.Opts, CommandParser.Args]] result_sql: List[Tuple[Any, ...]] if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) # Get command and parameters. result = self.command_parser.parse(message['command']) if result is None: return Response.command_not_found(message) command, _, args = result if command == 'list': result_sql = self._db.execute(self._list_sql) response: str = 'Alert word or phrase | Emoji\n---- | ----' for (phrase, emoji) in result_sql: response += '\n`{0}` | {1} :{1}:'.format(phrase, emoji) return Response.build_message(message, response) # Use lowercase -> no need for case insensitivity. alert_phrase: str = args.alert_phrase.lower() if command == 'add': # Add binding to database or update it. self._db.execute(self._update_sql, alert_phrase, args.emoji, commit = True) elif command == 'remove': self._db.execute(self._remove_sql, alert_phrase, commit = True) return Response.ok(message)
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) # Ask the parent process to restart. os.kill(os.getpid(), signal.SIGUSR1) # dead code return Response.none()
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) stream_regexes: Optional[List[Any]] = split( message['command'], converter=[validate_and_return_regex]) if stream_regexes is None or None in stream_regexes: return Response.build_message( message, 'Found invalid regular expressions.') response: List[str] = [] for stream_regex in stream_regexes: streams: List[str] = self.client.get_streams_from_regex( stream_regex) removed: int = 0 for stream in streams: result: Dict[str, Any] = self.client.get_stream_id(stream) if result['result'] != 'success': continue stream_id: int = result['stream_id'] # Check if stream is empty. result = self.client.get_messages({ 'anchor': 'oldest', 'num_before': 0, 'num_after': 1, 'narrow': [{ 'operator': 'stream', 'operand': stream_id }] }) if result['result'] != 'success' or result['messages']: continue # Archive the stream: https://zulip.com/help/archive-a-stream result = self.client.delete_stream(stream_id) if result['result'] == 'success': removed += 1 response.append('"%s" - found %d matching streams, removed %d' % (stream_regex, len(streams), removed)) return Response.build_message(message, '\n'.join(response))
def subscribe_all_users( self, message: Dict[str, Any], dest_stream: str, ) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) result: Dict[str, Any] = self.client.get_users() if result['result'] != 'success': return Response.error(message) user_ids: List[int] = [user['user_id'] for user in result['members']] if not self.client.subscribe_users(user_ids, dest_stream): return Response.error(message) return Response.ok(message)
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: result_sql: List[Tuple[Any, ...]] if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) try: if message['command'] == 'list': result_sql = self._db.execute(self._list_sql) else: result_sql = self._db.execute(message['command']) except Exception as e: return Response.build_message(message, str(e)) result: str = '```text\n' + '\n'.join(map(str, result_sql)) + '\n```' return Response.build_message(message, result)
def subscribe_streams( self, message: Dict[str, Any], dest_stream: str, streams: List[str]) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) failed: List[str] = [] for stream in streams: if not self.client.subscribe_all_from_stream_to_stream( stream, dest_stream, None): failed.append(stream) if not failed: return Response.ok(message) return Response.build_message( message, 'Failed to subscribe the following streams:\n' + '\n'.join(failed))
def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: result: Optional[Tuple[str, CommandParser.Opts, CommandParser.Args]] # Get command and parameters. result = self.command_parser.parse(message['command']) if result is None: return Response.command_not_found(message) command, _, args = result if command == 'subscribe': return self._subscribe(message['sender_id'], args.group_id, message) if command == 'unsubscribe': return self._unsubscribe(message['sender_id'], args.group_id, message) if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) if command == 'list': return self._list(message) if command == 'announce': if message['type'] != 'stream': return Response.build_message(message, 'Claim only stream messages.') return self._announce(message) if command == 'unannounce': return self._unannounce(message, args.message_id) if command == 'claim': if message['type'] != 'stream': return Response.build_message(message, 'Claim only stream messages.') return self._claim(message, args.group_id) if command == 'unclaim': return self._unclaim(message, args.group_id, args.message_id) if command == 'add': return self._add(message, args.group_id, args.emoji) if command == 'remove': return self._remove(message, args.group_id) if command in ['add_streams', 'remove_streams']: return self._change_streams(message, args.group_id, command, args.streams) return Response.command_not_found(message)
def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: result: Optional[Tuple[str, CommandParser.Opts, CommandParser.Args]] result_sql: List[Tuple[Any, ...]] if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) # Get command and parameters. result = self.command_parser.parse(message['command']) if result is None: return Response.command_not_found(message) command, _, args = result if command == 'list': response: str = '***List of Identifiers and Messages***\n' for (ident, text) in self._db.execute(self._list_sql): response += '\n--------\nTitle: **{}**\n{}'.format(ident, text) return Response.build_message(message, response) # Use lowercase -> no need for case insensitivity. ident = args.id.lower() if command == 'send': result_sql = self._db.execute(self._search_sql, ident) if not result_sql: return Response.command_not_found(message) # Remove requesting message. self.client.delete_message(message['id']) return Response.build_message(message, result_sql[0][0]) if command == 'add': self._db.execute(self._update_sql, ident, args.text, commit = True) return Response.ok(message) if command == 'remove': self._db.execute(self._delete_sql, ident, commit = True) return Response.ok(message) return Response.command_not_found(message)
def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) failed: List[str] = [] stream_tuples: Optional[List[Any]] = split( message['command'], converter = [lambda t: split(t, sep = ',', exact_split = 2)] ) if stream_tuples is None or None in stream_tuples: return Response.error(message) for old, new in stream_tuples: # Used for error messages. line: str = f'{old} -> {new}' try: old_id: int = self.client.get_stream_id(old)['stream_id'] except Exception as e: logging.exception(e) failed.append(line) continue result: Dict[str, Any] = self.client.update_stream( {'stream_id': old_id, 'new_name': '"{}"'.format(new)} ) if result['result'] != 'success': failed.append(line) if not failed: return Response.ok(message) response: str = 'Failed to perform the following renamings:\n' + '\n'.join(failed) return Response.build_message(message, response, msg_type = 'private')
def handle_message( self, message: Dict[str, Any], **kwargs: Any ) -> Union[Response, Iterable[Response]]: result: Optional[Tuple[str, CommandParser.Opts, CommandParser.Args]] if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) if 'stream_id' not in message: return Response.build_message(message, 'Error: Not a stream topic.') result = self.command_parser.parse('move ' + message['command']) if result is None: return Response.command_not_found(message) _, opts, args = result dest: str = ' '.join(args.dest) if opts.m is not None: return self._move_topic(message, dest, opts.m) return self._move_stream(message, dest)
def handle_message(self, message: Dict[str, Any], **kwargs: Any) -> Union[Response, Iterable[Response]]: if not self.client.user_is_privileged(message['sender_id']): return Response.admin_err(message) # Get the dirname of this file (which is located in the git repo). git_dir: Path = Path(__file__).parent.absolute() try: os.chdir(git_dir) except Exception as e: logging.exception(e) return Response.build_message( message, f'Cannot access the directory of my git repo {git_dir}. Please contact the admin.' ) # Execute command and capture stdout and stderr into one stream (stdout). try: result: sp.CompletedProcess[Any] = sp.run( self._git_pull_cmd, stdout=sp.PIPE, stderr=sp.STDOUT, text=True, timeout=self._timeout, ) except sp.TimeoutExpired: return Response.build_message( message, f'{self._git_pull_cmd} failed: timeout ({self._timeout} seconds) expired' ) return Response.build_message( message, f'Return code: {result.returncode}\nOutput:\n```text\n{result.stdout}\n```' )