Пример #1
0
    async def create(cls, contacts: List[Contact], topic: str) -> Room:
        """
        create room instance
        """
        if not hasattr(contacts, '__len__'):
            raise WechatyOperationError('contacts should be list type')
        if len(contacts) < 2:
            raise WechatyOperationError(
                'contactList need at least 2 contact to create a new room'
            )

        log.info(
            'Room create <%s - %s>',
            ','.join([contact.contact_id for contact in contacts]),
            topic
        )

        try:
            contact_ids = list(map(lambda x: x.contact_id, contacts))
            room_id = await cls.get_puppet(). \
                room_create(contact_ids=contact_ids, topic=topic)
            room = cls.load(room_id=room_id)
            await room.ready()
            return room
        except Exception as exception:
            message = 'Room create error <%s>' % str(exception.args)
            log.error(message)
            raise WechatyOperationError(message)
Пример #2
0
    async def qr_code(self) -> str:
        """
        Return the qrcode of ContactSelf
        
        Examples:
            >>> contact_self = bot.contact_self()
            >>> qr_code = await contact_self.qr_code()

        Raises:
            WechatyOperationError: if there is login exception, it will not get the qrcode
            WechatyOperationError: if the contact is not self, it will not get the qrcode

        Returns:
            str: the content of qrcode
        """
        try:
            contact_id: str = self.puppet.self_id()
        except Exception:
            raise WechatyOperationError(
                'Can not get qr_code, user might be either not logged in or already logged out'
            )

        if self.contact_id != contact_id:
            raise WechatyOperationError(
                'only can get qr_code for the login user self')
        qr_code_value = await self.puppet.contact_self_qr_code()
        return qr_code_value
Пример #3
0
    async def to_recalled(self) -> Message:
        """
        Get the recalled message

        Args:
            None
        Examples:
            >>> msg.to_recalled()
        Returns:
            Message: the recalled message
        """
        if self.message_type() != MessageType.MESSAGE_TYPE_RECALLED:
            raise WechatyOperationError(
                'Can not call toRecalled() on message which is not'
                ' recalled type.')

        origin_message_id = self.text()
        if origin_message_id is None:
            raise WechatyPayloadError('Can not find recalled message')

        log.info('get recall message <%s>', origin_message_id)
        try:
            message = self.wechaty.Message.load(origin_message_id)
            await message.ready()
            return message
        except Exception as exception:
            error_info = 'can"t load or ready message payload {}'.format(
                str(exception.args))

            log.error(error_info)
            raise WechatyOperationError(error_info)
    async def qr_code(self) -> str:
        """

        :return:
        """
        try:
            puppet_id: str = self.puppet.self_id()
        except Exception:
            raise WechatyOperationError(
                'Can not get qr_code, user might be either not logged in or already logged out')

        if self.contact_id != puppet_id:
            raise WechatyOperationError('only can get qr_code for the login user self')
        qr_code_value = await self.puppet.contact_self_qr_code()
        return qr_code_value
Пример #5
0
    async def forward(self, to: Union[Room, Contact]) -> None:
        """
        Forward a message to a room or a contact.
        Args:
            to: the room or contact to forward to
        Examples:
            >>> msg.forward(room)
            >>> msg.forward(contact)
        """
        log.info('forward() <%s>', to)
        if to is None:
            raise WechatyPayloadError('to param not found')
        try:
            if isinstance(to, Room):
                to_id = to.room_id
            elif isinstance(to, Contact):
                to_id = to.contact_id
            else:
                raise WechatyPayloadError(
                    'expected type is <Room, Contact>, but get <%s>' %
                    to.__class__)
            print(to_id)
            await self.puppet.message_forward(to_id, self.message_id)

        # pylint:disable=W0703
        except Exception as exception:
            message = 'Message forward error <%s>' % exception.args
            log.error(message)
            raise WechatyOperationError(message)
Пример #6
0
    async def to_file_box(self) -> FileBox:
        """
        Extract the Media File from the Message, and put it into the FileBox.

        Notes:
            ```
            File MessageType is : {
                MESSAGE_TYPE_ATTACHMENT,
                MESSAGE_TYPE_EMOTICON,
                MESSAGE_TYPE_IMAGE,
                MESSAGE_TYPE_VIDEO
            }
            ```
        Examples:
            >>> msg.to_file_box()
        Returns:
            FileBox: file box
        """
        log.info('Message to FileBox')
        if self.type() not in SUPPORTED_MESSAGE_FILE_TYPES:
            raise WechatyOperationError(
                f'this type <{self.type().name}> message can"t be converted to '
                f'FileBox')
        msg_type: MessageType = self.type()
        if msg_type == MessageType.MESSAGE_TYPE_IMAGE:
            file_box = await self.puppet.message_image(self.message_id)
        else:
            file_box = await self.puppet.message_file(self.message_id)

        return file_box
Пример #7
0
    async def forward(self, to: Union[Room, Contact]):
        """
        doc
        :param to:
        :return:
        """
        log.info('forward() <%s>', to)
        if to is None:
            raise WechatyPayloadError('to param not found')
        try:
            if isinstance(to, Room):
                to_id = to.room_id
            elif isinstance(to, Contact):
                to_id = to.contact_id
            else:
                raise WechatyPayloadError(
                    'expected type is <Room, Contact>, but get <%s>' %
                    to.__class__)
            print(to_id)
            await self.puppet.message_forward(to_id, self.message_id)

        # pylint:disable=W0703
        except Exception as exception:
            message = 'Message forward error <%s>' % exception.args
            log.error(message)
            raise WechatyOperationError(message)
Пример #8
0
    async def avatar(self, file_box: Optional[FileBox] = None) -> FileBox:
        """get avatar of ContactSelf

        Args:
            file_box (Optional[FileBox], optional): i. Defaults to None.

        Examples:
            >>> contact_self = bot.contact_self()
            >>> file_box = await contact_self.avatar()

        Raises:
            WechatyOperationError: _description_

        Returns:
            FileBox: _description_
        """
        log.info('avatar(%s)' % file_box.name if file_box else '')
        if not file_box:
            file_box = await super().avatar(None)
            return file_box

        if self.contact_id != self.puppet.self_id():
            raise WechatyOperationError(
                'set avatar only available for user self')

        await self.puppet.contact_avatar(self.contact_id, file_box)
Пример #9
0
    async def accept(self) -> None:
        """
        accept friendship
        Args:
            None
        Examples:
            >>> await friendship.accept()
        Returns:
            None
        """
        log.info('accept friendship, friendship_id: <%s>', self.friendship_id)
        if self.type() != FriendshipType.FRIENDSHIP_TYPE_RECEIVE:
            raise WechatyOperationError(
                'accept() need type to be FriendshipType.'
                'FRIENDSHIP_TYPE_RECEIVE, but it got a " + FriendshipType : '
                '<{0}>'.format(self.type().name))

        log.info('friendship accept to %s', self.payload.contact_id)
        await self.puppet.friendship_accept(friendship_id=self.friendship_id)
        contact = self.contact()

        # reset contact data
        try:
            # TODO -> some other logical code
            await contact.ready()
        # pylint:disable=W0703
        except Exception as e:
            log.info("can't reload contact data %s", str(e.args))
Пример #10
0
    async def avatar(self, file_box: Optional[FileBox] = None) -> FileBox:
        """
        Get or set avatar of ContactSelf.

        Args:
            file_box: FileBox object, if not provided, it will return a FileBox object

        Examples:
            >>> contact_self = bot.contact_self()
            >>> file_box = await contact_self.avatar()
            >>> file_box = await contact_self.avatar(file_box)

        Raises:
            WechatyOperationError: if the contact is not self, it will not get the avatar

        Returns:
            FileBox: file_box
        """
        log.info('avatar(%s)' % file_box.name if file_box else '')
        if not file_box:
            file_box = await super().avatar(None)
            return file_box

        if self.contact_id != self.puppet.self_id():
            raise WechatyOperationError(
                'set avatar only available for user self')

        await self.puppet.contact_avatar(self.contact_id, file_box)
Пример #11
0
    async def signature(self, signature: str) -> Any:
        """
        Set the signature of login contact.

        Args:
            signature: new signature

        Examples:
            >>> contact_self = bot.contact_self()
            >>> await contact_self.signature('new signature')
        
        Raises:
            WechatyOperationError: if there is login exception, it will not set the signature
            WechatyOperationError: if the contact is not self, it will not set the signature
        
        Returns:
            Any: the signature of login user
        """
        puppet_id = self.puppet.self_id()

        if self.contact_id != puppet_id:
            raise WechatyOperationError(
                'only can get qr_code for the login user self')

        return self.puppet.contact_signature(signature)
Пример #12
0
    async def say(
            self,
            some_thing: Union[str, Contact, FileBox, MiniProgram, UrlLink],
            mention_ids: Optional[List[str]] = None) -> Union[None, Message]:
        """
        Room Say(%s, %s)
        """
        log.info('Room say <%s, %s>', some_thing, mention_ids)

        if not some_thing:
            log.error('can"t say nothing')
            return None

        # we should import UrlLink type locally because of circular dependency

        from wechaty.user.url_link import UrlLink
        from wechaty.user.mini_program import MiniProgram
        from wechaty.user.contact import Contact
        if isinstance(some_thing, str):
            if mention_ids:
                mention_info = []
                for mention_id in mention_ids:
                    mention_contact: Contact = self.wechaty.Contact.load(
                        mention_id)
                    await mention_contact.ready()
                    alias = await mention_contact.alias()
                    name = mention_contact.name
                    mention_info.append('@' + (alias or name))

                mention_text = AT_SEPARATOR.join(mention_info)
                some_thing = mention_text + ' ' + some_thing

            msg_id = await self.puppet.message_send_text(
                conversation_id=self.room_id,
                message=some_thing,
                mention_ids=mention_ids)
        elif isinstance(some_thing, FileBox):
            msg_id = await self.puppet.message_send_file(
                conversation_id=self.room_id, file=some_thing)
        elif isinstance(some_thing, Contact):
            msg_id = await self.puppet.message_send_contact(
                conversation_id=self.room_id, contact_id=some_thing.contact_id)
        elif isinstance(some_thing, UrlLink):
            msg_id = await self.puppet.message_send_url(
                conversation_id=self.room_id,
                url=json.dumps(dataclasses.asdict(some_thing.payload)))
        elif isinstance(some_thing, MiniProgram):
            # TODO -> mini_program key is not clear
            assert some_thing.payload is not None
            msg_id = await self.puppet.message_send_mini_program(
                conversation_id=self.room_id, mini_program=some_thing.payload)
        else:
            raise WechatyOperationError('arg unsupported: ', some_thing)

        if msg_id is not None:
            msg = self.wechaty.Message.load(msg_id)
            await msg.ready()
            return msg
        return None
Пример #13
0
    def name(self, name: Optional[str]):
        puppet_id: str = self.puppet.self_id()

        if self.contact_id != puppet_id:
            raise WechatyOperationError(
                'only can get qr_code for the login user self')

        asyncio.run(self.puppet.contact_self_name(name))
Пример #14
0
 async def to_file_box(self) -> FileBox:
     """
     Extract the Media File from the Message, and put it into the FileBox.
     """
     log.info('Message to FileBox')
     if self.type() == MessageType.MESSAGE_TYPE_TEXT:
         raise WechatyOperationError(
             'text message can"t convert to FileBox')
     file_box = await self.puppet.message_file(self.message_id)
     return file_box
Пример #15
0
 def to_image(self) -> Image:
     """
     Extract the Image File from the Message, so that we can use
     different image sizes.
     :return:
     """
     log.info('Message to Image() for message %s', self.message_id)
     if self.type() != MessageType.MESSAGE_TYPE_IMAGE:
         raise WechatyOperationError(
             'current message type: %s, not image type' % self.type())
     return self.wechaty.Image.create(self.message_id)
Пример #16
0
    async def delete(self, contact: Contact) -> None:
        """
        Delete contact in a room
        """
        log.info('Room delete<%s>', contact)

        if contact is None or contact.contact_id is None:
            raise WechatyOperationError('Contact is none or contact_id not found')
        await self.puppet.room_delete(self.room_id, contact.contact_id)
        # reload the payload
        await self.ready(force_sync=True)
    async def signature(self, signature: str) -> Any:
        """

        :param signature:
        :return:
        """
        puppet_id = self.puppet.self_id()

        if self.contact_id != puppet_id:
            raise WechatyOperationError('only can get qr_code for the login user self')

        return self.puppet.contact_signature(signature)
Пример #18
0
    def _filter_contacts(
        cls, contacts: List[Contact], query: Union[str, ContactQueryFilter,
                                                   Callable[[Contact], bool]]
    ) -> List[Contact]:

        func: Callable[[Contact], bool]
        if isinstance(query, str):

            def filter_func(contact: Contact) -> bool:
                payload = contact.payload
                if not payload:
                    return False
                if query in payload.alias or query in payload.name:
                    return True
                if query == payload.id or quit == payload.weixin:
                    return True
                return False

            func = filter_func

        elif isinstance(query, ContactQueryFilter):

            def filter_func(contact: Contact) -> bool:
                payload = contact.payload

                # to pass the type checking
                assert isinstance(query, ContactQueryFilter)
                if not payload:
                    return False

                if query.alias and query.alias in payload.alias:
                    return True
                if query.name and query.name in payload.name:
                    return True

                if query.id and query.id == payload.id:
                    return True
                if query.weixin and query.weixin == payload.weixin:
                    return True

                return False

            func = filter_func
        elif isinstance(types, types.FunctionType):
            func = query
        else:
            raise WechatyOperationError(
                f'Query Argument<{query}> is not correct')

        assert not not func
        contacts = list(filter(func, contacts))
        return contacts
Пример #19
0
    async def to_mini_program(self) -> MiniProgram:
        """
        get message mini_program
        :return:
        """
        log.info('Message to MiniProgram <%s>', self.message_id)

        if self.type() != MessageType.MESSAGE_TYPE_MINI_PROGRAM:
            raise WechatyOperationError('not a mini_program type message')

        payload = await self.puppet.message_mini_program(self.message_id)
        if payload is None:
            raise WechatyPayloadError('no miniProgram payload for message %s' %
                                      self.message_id)
        return MiniProgram(payload)
Пример #20
0
 async def to_url_link(self) -> UrlLink:
     """
     get url_link from message
     :return:
     """
     log.info('Message to UrlLink')
     if self.type() != MessageType.MESSAGE_TYPE_URL:
         raise WechatyOperationError(
             'current message type: %s, not url type' % self.type())
     payload = await self.puppet.message_url(self.message_id)
     if payload is None:
         raise WechatyPayloadError(
             'can not get url_link_payload by message: %s' %
             self.message_id)
     return UrlLink(payload)
Пример #21
0
    async def say(
        self, message: Union[str, Message, FileBox, Contact, UrlLink]
    ) -> Optional[Message]:
        """
        say something
        :param message: message content
        """
        if not message:
            log.error('can"t say nothing')
            return None

        if not self.is_ready():
            await self.ready()

        # import some class because circular dependency
        from wechaty.user.url_link import UrlLink

        if isinstance(message, str):
            # say text
            msg_id = await self.puppet.message_send_text(
                conversation_id=self.contact_id, message=message)
        elif isinstance(message, Contact):
            msg_id = await self.puppet.message_send_contact(
                contact_id=message.contact_id, conversation_id=self.contact_id)

        elif isinstance(message, FileBox):
            msg_id = await self.puppet.message_send_file(
                conversation_id=self.contact_id, file=message)

        elif isinstance(message, UrlLink):
            # use this way to resolve circulation dependency import
            msg_id = await self.puppet.message_send_url(
                conversation_id=self.contact_id,
                url=json.dumps(dataclasses.asdict(message.payload)))
        # elif isinstance(message, MiniProgram):
        #     msg_id = await self.puppet.message_send_mini_program(
        #         self.contact_id, message.payload)

        else:
            log.info('unsupported tags %s', message)
            raise WechatyOperationError('unsupported tags')

        if msg_id is not None:
            msg = self.wechaty.Message.load(msg_id)
            await msg.ready()
            return msg

        return None
Пример #22
0
    def _filter_rooms(
        cls, rooms: List[Room], query: Union[str, RoomQueryFilter,
                                             Callable[[Room],
                                                      bool]]) -> List[Room]:
        """
        filter rooms with query which can be string, RoomQueryFilter, or callable<filter> function

        Args:
            rooms: list of room
            query:  the query message
        Returns: the filtered contacts
        """
        func: Callable[[Room], bool]

        if isinstance(query, str):

            def filter_func(room: Room) -> bool:
                payload = room.payload
                if not payload:
                    return False
                if query == payload.id or query in payload.topic:
                    return True
                return False

            func = filter_func
        elif isinstance(query, RoomQueryFilter):

            def filter_func(room: Room) -> bool:
                # to pass the type checking
                assert isinstance(query, RoomQueryFilter)
                payload = room.payload
                if not payload:
                    return False

                if query.id == payload.id or query.topic in payload.topic:
                    return True
                return False

            func = filter_func
        elif isinstance(query, types.FunctionType):
            func = query
        else:
            raise WechatyOperationError(
                f'Query Argument<{query}> is not correct')

        assert not not func
        rooms = list(filter(func, rooms))
        return rooms
Пример #23
0
    async def avatar(self, file: Optional[FileBox] = None) -> FileBox:
        """

        :param file:
        :return:
        """
        log.info('Contact', 'avatar(%s)' % file.name if file else '')
        if not file:
            file_box = await super().avatar(None)
            return file_box

        if self.contact_id != self.puppet.self_id():
            raise WechatyOperationError(
                'set avatar only available for user self')

        await self.puppet.contact_avatar(self.contact_id, file)
Пример #24
0
    async def to_contact(self) -> Contact:
        """
        Get Share Card of the Message
        Extract the Contact Card from the Message, and encapsulate it into
         Contact class
        :return:
        """
        log.info('Message to Contact')
        if self.type() != MessageType.MESSAGE_TYPE_CONTACT:
            raise WechatyOperationError(
                'current message type: %s, not contact type' % self.type())

        contact_id = await self.puppet.message_contact(self.message_id)

        contact = self.wechaty.Contact.load(contact_id)
        await contact.ready()
        return contact
Пример #25
0
    async def delete(self, target: Union[Contact, Favorite]):
        """
        remove tag from contact or favorite
        :param target:
        :return:
        """
        log.info('delete tag %s', self.tag_id)

        if target is Contact:
            await self.puppet.tag_contact_delete(tag_id=self.tag_id)
        elif target is Favorite:
            # TODO -> tag_favorite_delete not implement
            pass
            # await self.puppet.tag_contact_delete()
        else:
            raise WechatyOperationError(
                'target param is required to be Contact or Favorite object')
Пример #26
0
    async def alias(self, member: Contact) -> Optional[str]:
        """
        Return contact's roomAlias in the room

        TODO -> 'Wechaty Puppet Unsupported API Error. Learn More At
        https://github.com/wechaty/wechaty-puppet/wiki/Compatibility', None)>

        the result of the function will always return an empty string
        """
        if member is None:
            raise WechatyOperationError('member can"t be none')
        room_member_payload = await self.puppet.room_member_payload(
            room_id=self.room_id, contact_id=member.contact_id)

        if room_member_payload is not None \
            and room_member_payload.room_alias is not None:
            return room_member_payload.room_alias
        return None
Пример #27
0
 async def accept(self) -> None:
     """
     accept the room invitation
     """
     log.info('accept() <%s>', self)
     await self.puppet.room_invitation_accept(
         room_invitation_id=self.invitation_id)
     inviter = await self.inviter()
     topic = await self.topic()
     try:
         await inviter.ready()
         log.info('accept() with room(%s) & inviter(%s) ready())', topic,
                  inviter)
     except Exception as exception:
         message = 'accept() with room(%s) & inviter(%s) error' % (topic,
                                                                   inviter)
         log.error(message)
         raise WechatyOperationError(message)
Пример #28
0
    async def to_file_box(self) -> FileBox:
        """
        Extract the Media File from the Message, and put it into the FileBox.

        File MessageType is : {
            MESSAGE_TYPE_ATTACHMENT,
            MESSAGE_TYPE_EMOTICON,
            MESSAGE_TYPE_IMAGE,
            MESSAGE_TYPE_VIDEO
        }
        """
        log.info('Message to FileBox')
        if self.type() not in SUPPORTED_MESSAGE_FILE_TYPES:
            raise WechatyOperationError(
                f'this type <{self.type().name}> message can"t be converted to '
                f'FileBox')
        file_box = await self.puppet.message_file(self.message_id)
        return file_box
Пример #29
0
    def remove(self, source: Union[Contact, Favorite]):
        """
        Remove this tag from Contact/Favorite

        tips : This function is depending on the Puppet Implementation,
        see [puppet-compatible-table](https://github.com/wechaty/
        wechaty/wiki/Puppet#3-puppet-compatible-table)
        :param source:
        :return:
        """
        log.info('remove tag for %s with %s', self.tag_id, str(source))
        try:
            if isinstance(source, Contact):
                self.puppet.tag_contact_remove(tag_id=self.tag_id,
                                               contact_id=source.contact_id)
            elif isinstance(source, Favorite):
                # TODO -> tag_favorite_remove not implement
                pass
        except Exception as e:
            log.info('remove exception %s', str(e.args))
            raise WechatyOperationError('remove error')
Пример #30
0
    async def say(self, message: Union[str, Message, FileBox, Contact, UrlLink, MiniProgram]
                  ) -> Optional[Message]:
        """say something to contact, which can be text, image, file, contact, url

        Note:
            Its implementation depends on the puppet, so if you want to use this method, please check
            [Puppet](https://github.com/wechaty/wechaty/wiki/Puppet#3-puppet-compatible-table).

        Args:
            message: the message object to be sended to contact
        
        Examples:
            >>> contact = Contact.load('contact-id')
            >>> await contact.say('hello')
            >>> await contact.say(FileBox.from_file('/path/to/file'))
            >>> await contact.say(contact)
            >>> await contact.say(UrlLink('https://wechaty.js.org'))

            >>> # the data format of mini program should pre-stored
            >>> await contact.say(MiniProgram('username', 'appid'))

        Returns:
            Message: if the message is send successfully, return the message object, otherwise return None 
        """
        if not message:
            log.error('can"t say nothing')
            return None

        if not self.is_ready():
            await self.ready()

        # import some class because circular dependency
        from wechaty.user.url_link import UrlLink   # pylint: disable=import-outside-toplevel

        if isinstance(message, str):
            # say text
            msg_id = await self.puppet.message_send_text(
                conversation_id=self.contact_id,
                message=message
            )
        elif isinstance(message, Contact):
            msg_id = await self.puppet.message_send_contact(
                contact_id=message.contact_id,
                conversation_id=self.contact_id
            )

        elif isinstance(message, FileBox):
            msg_id = await self.puppet.message_send_file(
                conversation_id=self.contact_id,
                file=message
            )

        elif isinstance(message, UrlLink):
            # use this way to resolve circulation dependency import
            msg_id = await self.puppet.message_send_url(
                conversation_id=self.contact_id,
                url=json.dumps(dataclasses.asdict(message.payload), ensure_ascii=False)
            )
        elif isinstance(message, MiniProgram):
            msg_id = await self.puppet.message_send_mini_program(
                conversation_id=self.contact_id,
                mini_program=message.payload
            )

        else:
            log.info('unsupported tags %s', message)
            raise WechatyOperationError('unsupported tags')

        if msg_id is not None:
            msg = self.wechaty.Message.load(msg_id)
            await msg.ready()
            return msg

        return None