Esempio n. 1
0
    def _announce(
        self,
        message: Dict[str, Any]
    ) -> Union[Response, Iterable[Response]]:
        table: str = '\n'.join(
            self._announcement_msg_table_row_fmt % (group_id, emoji)
            for group_id, emoji, _ in self._db.execute(self._list_sql)
        )

        # Remove the requesting message.
        self.client.delete_message(message['id'])

        # Send own message.
        result: Dict[str, Any] = self.client.send_response(
            Response.build_message(message, self._announcement_msg.format(table))
        )
        if result['result'] != 'success':
            return Response.none()

        # Insert the id of the bot's message into the database.
        try:
            self._db.execute(self._claim_all_sql, result['id'], commit = True)
        except Exception as e:
            return Response.build_message(message, str(e))

        # Get all the currently existant emojis.
        result_sql: List[Tuple[Any, ...]] = self._db.execute(self._get_all_emojis_sql)
        if not result_sql:
            return Response.none()

        # React with all those emojis on this message.
        for emoji in map(lambda t: cast(str, t[0]), result_sql):
            self.client.send_response(Response.build_reaction_from_id(result['id'], emoji))

        return Response.none()
Esempio n. 2
0
    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)
Esempio n. 3
0
    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']))
Esempio n. 4
0
    def _move_topic(
        self,
        message: Dict[str, Any],
        dest: str,
        count: int
    ) -> Union[Response, Iterable[Response]]:
        if count < 1:
            return Response.build_message(message, 'Error: Message count must be >= 1.')

        # Get the stream id ...
        stream_id: int = message['stream_id']
        # ... and the topic of the current message.
        topic: str = message['subject']

        # Get the message that is count "hops" before the given message
        # in this topic.
        request: Dict[str, Any] = {
            'anchor': 'newest',
            'num_before': count + 1,
            'num_after': 0,
            'narrow': [
                {'operator': 'stream', 'operand': stream_id},
                {'operator': 'topic', 'operand': topic},
                {'operator': 'near', 'operand': str(message['id'])}
            ]
        }
        result = self.client.get_messages(request)
        if result['result'] != 'success':
            return Response.error(message)
        if len(result['messages']) < 2:
            return Response.build_message(message, 'No message to move.')
        first_message: Dict[str, Any] = result['messages'][0]

        # Move message (and all following in the same topic) to the new topic.
        request = {
            'message_id': first_message['id'],
            'topic': dest,
            'stream_id': stream_id,
            'send_notification_to_old_thread': False,
            'send_notification_to_new_thread': False,
            'propagate_mode': 'change_later'
        }
        result = self.client.update_message(request)
        if result['result'] != 'success':
            return Response.error(message)

        # Remove requesting message.
        self.client.delete_message(message['id'])

        # Get current stream name.
        stream_name: Optional[str] = self.client.get_stream_name(stream_id)
        from_loc: str = (stream_name if stream_name is not None else "unknown") + ">" + topic
        to_loc: str = (stream_name if stream_name is not None else "unknown") + ">" + dest

        return Response.build_message(
            first_message,
            self.msg_template_topic.format(first_message['sender_full_name'], from_loc, to_loc),
            msg_type = 'private'
        )
Esempio n. 5
0
    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))
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)
Esempio n. 8
0
    def _list(
        self,
        message: Dict[str, Any]
    ) -> Union[Response, Iterable[Response]]:
        """Command `group list`."""
        response: str = 'Group Id | Emoji | Streams | ClaimedBy\n---- | ---- | ---- | ----'

        for (group_id, emoji, streams) in self._db.execute(self._list_sql):
            streams_concat: str = ', '.join(
                '"{}"'.format(s) for s in streams.split('\n')
            )
            claims: str = ', '.join([
                self.message_link.format(msg_id)
                for (msg_id,) in self._db.execute(self._get_claims_for_group, group_id)
            ])
            response += '\n{0} | {1} :{1}: | `{2}` | {3}'.format(
                group_id, emoji, streams_concat, claims
            )

        response += '\n\nMessages claimed for all groups: ' + ', '.join(
            self.message_link.format(msg_id)
            for msg_id, in self._db.execute(self._get_claims_for_all_sql)
        )

        return Response.build_message(message, response)
Esempio n. 9
0
    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')
Esempio n. 10
0
    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]
        )
Esempio n. 11
0
    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)
Esempio n. 12
0
    def _move_stream(
        self,
        message: Dict[str, Any],
        dest: str
    ) -> Union[Response, Iterable[Response]]:
        # Get destination stream name.
        dest_stream: Optional[str] = Regex.get_stream_name(dest)
        if dest_stream is None:
            return Response.command_not_found(message)

        # Get destination stream id.
        result: Dict[str, Any] = self.client.get_stream_id(dest_stream)
        if result['result'] != 'success':
            return Response.error(message)
        dest_stream_id: int = result['stream_id']

        # Get the stream id ...
        src_stream_id: int = message['stream_id']
        # ... and the topic of the current message.
        topic: str = message['subject']

        # Get message which started the topic.
        request: Dict[str, Any] = {
            'anchor': 'oldest',
            'num_before': 0,
            'num_after': 1,
            'narrow': [
                { 'operator': 'stream', 'operand': src_stream_id },
                { 'operator': 'topic', 'operand': topic }
            ]
        }
        result = self.client.get_messages(request)
        if result['result'] != 'success':
            return Response.error(message)
        first_message: Dict[str, Any] = result['messages'][0]

        # Move message (and all following in the same topic) = move topic.
        request = {
            'message_id': first_message['id'],
            'topic': topic,
            'stream_id': dest_stream_id,
            'send_notification_to_old_thread': False,
            'propagate_mode': 'change_all'
        }
        result = self.client.update_message(request)
        if result['result'] != 'success':
            return Response.error(message)

        # Remove requesting message.
        self.client.delete_message(message['id'])

        return Response.build_message(
            first_message,
            self.msg_template_stream.format(first_message['sender_full_name'], topic, dest_stream),
            msg_type = 'private'
        )
Esempio n. 13
0
    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)
Esempio n. 14
0
    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)
Esempio n. 15
0
    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)
Esempio n. 16
0
    def _help_overview(
            self, message: Dict[str,
                                Any]) -> Union[Response, Iterable[Response]]:
        # Get the command names.
        help_message: str = '\n'.join(
            map(lambda tuple: '- ' + tuple[0], self.help_info))

        return Response.build_message(message,
                                      self._help_overview_template.format(
                                          message['sender_full_name'],
                                          help_message),
                                      msg_type='private',
                                      to=message['sender_email'])
Esempio n. 17
0
    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)
Esempio n. 18
0
 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]
     )
Esempio n. 19
0
 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)
Esempio n. 20
0
    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```'
        )
Esempio n. 21
0
    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)
Esempio n. 22
0
    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.'
        )
Esempio n. 23
0
    def _help_command(self, message: Dict[str, Any],
                      command: str) -> Union[Response, Iterable[Response]]:
        info_tuple: Optional[Tuple[str, str, str]] = None

        for ituple in self.help_info:
            if ituple[0] == command:
                info_tuple = ituple
                break
        if info_tuple is None:
            return Response.command_not_found(message)

        help_message: str = '\n'.join(info_tuple[1:])

        return Response.build_message(message,
                                      help_message,
                                      msg_type='private',
                                      to=message['sender_email'])
Esempio n. 24
0
 def handle_message(
     self,
     message: Dict[str, Any],
     **kwargs: Any
 ) -> Union[Response, Iterable[Response]]:
     # Get search string and quote it.
     search: str = urllib.parse.quote(message['command'], safe = '')
     # Fix strange behavior of Zulip which does not accept literal periods.
     search = search.replace('.', '%2E')
     # Get host url (removing trailing 'api/').
     base_url: str = self.client.base_url[:-4]
     # Build the full url.
     url: str = base_url + self.path + search
     # Remove requesting message.
     self.client.delete_message(message['id'])
     return Response.build_message(
         message, self.msg_template.format(url)
     )
Esempio n. 25
0
    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))
Esempio n. 26
0
    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')
Esempio n. 27
0
    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)
Esempio n. 28
0
 def handle_message(self, message: Dict[str, Any],
                    **kwargs: Any) -> Union[Response, Iterable[Response]]:
     return Response.build_message(message,
                                   'https://github.com/ro-i/tumcsbot')