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 _unannounce( self, message: Dict[str, Any], message_id: str ) -> Union[Response, Iterable[Response]]: self._db.execute(self._unclaim_msg_for_all_sql, message_id, commit = True) return Response.ok(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 subscribe_users( self, message: Dict[str, Any], dest_stream: str, users: List[Union[str, Tuple[str, Optional[int]]]] ) -> Union[Response, Iterable[Response]]: # First, get all the ids of the users whose ids we do not already know. user_ids: Optional[ List[int]] = self.client.get_user_ids_from_display_names( map( lambda o: o[0] if isinstance(o, tuple) else o, filter( lambda o: isinstance(o, str) or (isinstance(o, tuple) and o[1] is None), users))) if user_ids is None: return Response.build_message( message, 'error: could not get the user ids.') user_ids.extend( map( lambda t: cast(int, t[1]), filter( lambda o: isinstance(o, tuple) and isinstance(o[1], int), users))) 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]]: 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]]: 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 _claim( self, message: Dict[str, Any], group_id: Optional[str], ) -> Union[Response, Iterable[Response]]: """Command `group claim [id]`.""" if group_id: self._db.execute(self._claim_group_sql, message['id'], group_id, commit = True) else: self._db.execute(self._claim_all_sql, message['id'], commit = True) return Response.ok(message)
def _unsubscribe( self, user_id: int, group_id: str, message: Optional[Dict[str, Any]] = None ) -> Union[Response, Iterable[Response]]: """Unsubscribe a user from a group.""" self._db.execute(self._unsubscribe_user_sql, user_id, group_id, commit = True) if message is not None: return Response.ok(message) return Response.build_message( message = None, content = f'Unsubscribed from group {group_id}.', msg_type = 'private', to = [user_id] )
def _unclaim( self, message: Dict[str, Any], group_id: str, message_id: str ) -> Union[Response, Iterable[Response]]: try: msg_id: int = int(message_id) except ValueError: return Response.build_message(message, f'{message_id} is not an integer.') self._db.execute( self._unclaim_msg_from_group_sql, msg_id, group_id, commit = True ) return Response.ok(message)
def subscribe_user_emails( self, message: Dict[str, Any], dest_stream: str, user_emails: List[str]) -> Union[Response, Iterable[Response]]: user_ids: Optional[List[int]] = self.client.get_user_ids_from_emails( user_emails) if user_ids is None: return Response.build_message( message, 'error: could not get the user ids.') if not self.client.subscribe_users( user_ids, dest_stream, allow_private_streams=True): return Response.error(message) return Response.ok(message)
def _remove( self, message: Dict[str, Any], group_id: str, ) -> Union[Response, Iterable[Response]]: msg_success: bool = self._announcements_remove_group(group_id) self._db.execute(self._remove_sql, group_id, commit = True) if msg_success: return Response.ok(message) return Response.build_message( message, 'Group removed, but removal failed for some announcement messages.' )
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 _subscribe( self, user_id: int, group_id: str, message: Optional[Dict[str, Any]] = None ) -> Union[Response, Iterable[Response]]: """Subscribe a user to a group.""" msg: str try: self._db.execute(self._subscribe_user_sql, user_id, group_id, commit = True) except IntegrityError as e: logging.exception(e) # User already subscribed. msg = f'I think you are already subscribed to group {group_id}.' if message: return Response.build_message(message, msg) return Response.build_message( message = None, content = msg, msg_type = 'private', to = [user_id] ) stream_regs: List[str] = [] for (stream_regs_str,) in self._db.execute(self._get_streams_sql, group_id): if not stream_regs_str: continue stream_regs.extend(stream_regs_str.split('\n')) no_success: List[str] = self._subscribe_users_to_stream_regexes([user_id], stream_regs) if not no_success: if message is not None: return Response.ok(message) return Response.build_message( message = None, content = f'Subscribed to group {group_id}.', msg_type = 'private', to = [user_id] ) msg = 'Failed to subscribe you to the following streams: %s.' % str(no_success) if message is not None: return Response.build_message(message, msg) # Write a private message to the user. return Response.build_message( message = None, content = msg, msg_type = 'private', to = [user_id] )
def _change_streams( self, message: Dict[str, Any], group_id: str, command: str, change_stream_regs: List[str] ) -> Union[Response, Iterable[Response]]: """Command `group (add_streams|remove_streams) <id> <stream>...`.""" # Validate the regexes. for reg in change_stream_regs: try: re.compile(reg) except re.error as e: return Response.build_message(message, 'invalid regex: %s\n%s', reg, str(e)) result_sql: List[Tuple[Any, ...]] = self._db.execute( self._get_streams_sql, group_id, commit = True ) if not result_sql: return Response.build_message(message, f'Group {group_id} does not exist.') # Current stream patterns. stream_list: List[str] = result_sql[0][0].split('\n') # The string containing the new list of stream patterns (newline separated). # The patterns have to be non-empty. new_streams: str = '\n'.join(filter( bool, set(stream_list + change_stream_regs) if command == 'add_streams' else [s for s in stream_list if s not in change_stream_regs] )) try: self._db.execute(self._update_streams_sql, new_streams, group_id, commit = True) except Exception as e: logging.exception(e) return Response.build_message(message, str(e)) # Subscribe the group subscribers to the new streams. self._subscribe_users_to_stream_regexes( self._get_group_subscribers([group_id]), change_stream_regs ) return Response.ok(message)
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]]: 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 _add( self, message: Dict[str, Any], group_id: str, emoji: str ) -> Union[Response, Iterable[Response]]: """Command `group add <id> <emoji>`.""" if '\n' in group_id: return Response.build_message(message, 'The group id must not contain newlines.') try: self._db.execute( self._insert_sql, group_id, emoji, '', commit = True ) except IntegrityError as e: return Response.build_message(message, str(e)) # Update the announcement messages. if not self._announcements_add_group(group_id): return Response.build_message( message, 'Group added, but announcement failed for some messages.' ) return Response.ok(message)