2018-04-05 21:14:22 +03:00
|
|
|
import datetime
|
|
|
|
|
|
|
|
from .common import EventBuilder, EventCommon, name_inner_event
|
2019-05-01 18:52:32 +03:00
|
|
|
from .. import utils
|
2018-04-05 21:14:22 +03:00
|
|
|
from ..tl import types
|
2019-03-26 11:18:18 +03:00
|
|
|
from ..tl.custom.sendergetter import SenderGetter
|
2018-04-05 21:14:22 +03:00
|
|
|
|
|
|
|
|
|
|
|
@name_inner_event
|
|
|
|
class UserUpdate(EventBuilder):
|
|
|
|
"""
|
2019-06-11 12:09:22 +03:00
|
|
|
Occurs whenever a user goes online, starts typing, etc.
|
2018-04-05 21:14:22 +03:00
|
|
|
"""
|
2018-07-19 02:47:32 +03:00
|
|
|
@classmethod
|
|
|
|
def build(cls, update):
|
2018-04-05 21:14:22 +03:00
|
|
|
if isinstance(update, types.UpdateUserStatus):
|
2018-07-19 02:47:32 +03:00
|
|
|
event = cls.Event(update.user_id,
|
|
|
|
status=update.status)
|
2019-03-26 10:57:16 +03:00
|
|
|
elif isinstance(update, types.UpdateChatUserTyping):
|
|
|
|
# Unfortunately, we can't know whether `chat_id`'s type
|
|
|
|
event = cls.Event(update.user_id,
|
|
|
|
chat_id=update.chat_id,
|
|
|
|
typing=update.action)
|
|
|
|
elif isinstance(update, types.UpdateUserTyping):
|
|
|
|
event = cls.Event(update.user_id,
|
|
|
|
typing=update.action)
|
2018-04-05 21:14:22 +03:00
|
|
|
else:
|
|
|
|
return
|
|
|
|
|
|
|
|
event._entities = update._entities
|
2018-07-11 12:22:43 +03:00
|
|
|
return event
|
2018-04-05 21:14:22 +03:00
|
|
|
|
2019-03-26 11:18:18 +03:00
|
|
|
class Event(EventCommon, SenderGetter):
|
2018-04-05 21:14:22 +03:00
|
|
|
"""
|
2019-06-11 12:09:22 +03:00
|
|
|
Represents the event of a user update
|
|
|
|
such as gone online, started typing, etc.
|
2018-04-05 21:14:22 +03:00
|
|
|
|
|
|
|
Members:
|
|
|
|
online (`bool`, optional):
|
|
|
|
``True`` if the user is currently online, ``False`` otherwise.
|
|
|
|
Might be ``None`` if this information is not present.
|
|
|
|
|
|
|
|
last_seen (`datetime`, optional):
|
|
|
|
Exact date when the user was last seen if known.
|
|
|
|
|
|
|
|
until (`datetime`, optional):
|
|
|
|
Until when will the user remain online.
|
|
|
|
|
|
|
|
within_months (`bool`):
|
|
|
|
``True`` if the user was seen within 30 days.
|
|
|
|
|
|
|
|
within_weeks (`bool`):
|
|
|
|
``True`` if the user was seen within 7 days.
|
|
|
|
|
|
|
|
recently (`bool`):
|
|
|
|
``True`` if the user was seen within a day.
|
|
|
|
|
|
|
|
action (:tl:`SendMessageAction`, optional):
|
|
|
|
The "typing" action if any the user is performing if any.
|
|
|
|
|
|
|
|
cancel (`bool`):
|
|
|
|
``True`` if the action was cancelling other actions.
|
|
|
|
|
|
|
|
typing (`bool`):
|
|
|
|
``True`` if the action is typing a message.
|
|
|
|
|
|
|
|
recording (`bool`):
|
|
|
|
``True`` if the action is recording something.
|
|
|
|
|
|
|
|
uploading (`bool`):
|
|
|
|
``True`` if the action is uploading something.
|
|
|
|
|
|
|
|
playing (`bool`):
|
|
|
|
``True`` if the action is playing a game.
|
|
|
|
|
|
|
|
audio (`bool`):
|
|
|
|
``True`` if what's being recorded/uploaded is an audio.
|
|
|
|
|
|
|
|
round (`bool`):
|
|
|
|
``True`` if what's being recorded/uploaded is a round video.
|
|
|
|
|
|
|
|
video (`bool`):
|
|
|
|
``True`` if what's being recorded/uploaded is an video.
|
|
|
|
|
|
|
|
document (`bool`):
|
|
|
|
``True`` if what's being uploaded is document.
|
|
|
|
|
|
|
|
geo (`bool`):
|
|
|
|
``True`` if what's being uploaded is a geo.
|
|
|
|
|
|
|
|
photo (`bool`):
|
|
|
|
``True`` if what's being uploaded is a photo.
|
|
|
|
|
|
|
|
contact (`bool`):
|
|
|
|
``True`` if what's being uploaded (selected) is a contact.
|
|
|
|
"""
|
2019-03-26 10:57:16 +03:00
|
|
|
def __init__(self, user_id, *, status=None, chat_id=None, typing=None):
|
2019-03-26 11:14:55 +03:00
|
|
|
if chat_id is None:
|
|
|
|
super().__init__(types.PeerUser(user_id))
|
|
|
|
else:
|
|
|
|
# Temporarily set the chat_peer to the ID until ._set_client.
|
|
|
|
# We need the client to actually figure out its type.
|
|
|
|
super().__init__(chat_id)
|
2019-03-26 10:57:16 +03:00
|
|
|
|
2019-05-12 15:00:12 +03:00
|
|
|
SenderGetter.__init__(self, user_id)
|
2019-03-26 11:18:18 +03:00
|
|
|
|
2018-04-05 21:14:22 +03:00
|
|
|
self.online = None if status is None else \
|
|
|
|
isinstance(status, types.UserStatusOnline)
|
|
|
|
|
|
|
|
self.last_seen = status.was_online if \
|
|
|
|
isinstance(status, types.UserStatusOffline) else None
|
|
|
|
|
|
|
|
self.until = status.expires if \
|
|
|
|
isinstance(status, types.UserStatusOnline) else None
|
|
|
|
|
|
|
|
if self.last_seen:
|
2018-07-24 21:38:38 +03:00
|
|
|
now = datetime.datetime.now(tz=datetime.timezone.utc)
|
|
|
|
diff = now - self.last_seen
|
2018-04-05 21:14:22 +03:00
|
|
|
if diff < datetime.timedelta(days=30):
|
|
|
|
self.within_months = True
|
|
|
|
if diff < datetime.timedelta(days=7):
|
|
|
|
self.within_weeks = True
|
|
|
|
if diff < datetime.timedelta(days=1):
|
|
|
|
self.recently = True
|
|
|
|
else:
|
|
|
|
self.within_months = self.within_weeks = self.recently = False
|
|
|
|
if isinstance(status, (types.UserStatusOnline,
|
|
|
|
types.UserStatusRecently)):
|
|
|
|
self.within_months = self.within_weeks = True
|
|
|
|
self.recently = True
|
|
|
|
elif isinstance(status, types.UserStatusLastWeek):
|
|
|
|
self.within_months = self.within_weeks = True
|
|
|
|
elif isinstance(status, types.UserStatusLastMonth):
|
|
|
|
self.within_months = True
|
|
|
|
|
|
|
|
self.action = typing
|
|
|
|
if typing:
|
|
|
|
self.cancel = self.typing = self.recording = self.uploading = \
|
|
|
|
self.playing = False
|
|
|
|
self.audio = self.round = self.video = self.document = \
|
|
|
|
self.geo = self.photo = self.contact = False
|
|
|
|
|
|
|
|
if isinstance(typing, types.SendMessageCancelAction):
|
|
|
|
self.cancel = True
|
|
|
|
elif isinstance(typing, types.SendMessageTypingAction):
|
|
|
|
self.typing = True
|
|
|
|
elif isinstance(typing, types.SendMessageGamePlayAction):
|
|
|
|
self.playing = True
|
|
|
|
elif isinstance(typing, types.SendMessageGeoLocationAction):
|
|
|
|
self.geo = True
|
|
|
|
elif isinstance(typing, types.SendMessageRecordAudioAction):
|
|
|
|
self.recording = self.audio = True
|
|
|
|
elif isinstance(typing, types.SendMessageRecordRoundAction):
|
|
|
|
self.recording = self.round = True
|
|
|
|
elif isinstance(typing, types.SendMessageRecordVideoAction):
|
|
|
|
self.recording = self.video = True
|
|
|
|
elif isinstance(typing, types.SendMessageChooseContactAction):
|
|
|
|
self.uploading = self.contact = True
|
|
|
|
elif isinstance(typing, types.SendMessageUploadAudioAction):
|
|
|
|
self.uploading = self.audio = True
|
|
|
|
elif isinstance(typing, types.SendMessageUploadDocumentAction):
|
|
|
|
self.uploading = self.document = True
|
|
|
|
elif isinstance(typing, types.SendMessageUploadPhotoAction):
|
|
|
|
self.uploading = self.photo = True
|
|
|
|
elif isinstance(typing, types.SendMessageUploadRoundAction):
|
|
|
|
self.uploading = self.round = True
|
|
|
|
elif isinstance(typing, types.SendMessageUploadVideoAction):
|
|
|
|
self.uploading = self.video = True
|
|
|
|
|
2019-03-26 11:14:55 +03:00
|
|
|
def _set_client(self, client):
|
|
|
|
if isinstance(self._chat_peer, int):
|
|
|
|
try:
|
2019-03-26 13:39:25 +03:00
|
|
|
chat = client._entity_cache[self._chat_peer]
|
2019-03-26 11:14:55 +03:00
|
|
|
if isinstance(chat, types.InputPeerChat):
|
|
|
|
self._chat_peer = types.PeerChat(self._chat_peer)
|
|
|
|
elif isinstance(chat, types.InputPeerChannel):
|
|
|
|
self._chat_peer = types.PeerChannel(self._chat_peer)
|
|
|
|
else:
|
|
|
|
# Should not happen
|
|
|
|
self._chat_peer = types.PeerUser(self._chat_peer)
|
2019-03-26 13:39:25 +03:00
|
|
|
except KeyError:
|
2019-03-26 11:14:55 +03:00
|
|
|
# Hope for the best. We don't know where this event
|
|
|
|
# occurred but it was most likely in a channel.
|
|
|
|
self._chat_peer = types.PeerChannel(self._chat_peer)
|
|
|
|
|
|
|
|
super()._set_client(client)
|
2019-05-01 18:52:32 +03:00
|
|
|
self._sender, self._input_sender = utils._get_entity_pair(
|
|
|
|
self.sender_id, self._entities, client._entity_cache)
|
2019-03-28 12:47:15 +03:00
|
|
|
|
2018-04-05 21:14:22 +03:00
|
|
|
@property
|
2018-06-25 12:03:20 +03:00
|
|
|
def user(self):
|
2019-05-09 13:24:37 +03:00
|
|
|
"""Alias for `sender <telethon.tl.custom.sendergetter.SenderGetter.sender>`."""
|
2019-03-26 11:18:18 +03:00
|
|
|
return self.sender
|
2018-06-25 12:03:20 +03:00
|
|
|
|
|
|
|
async def get_user(self):
|
2019-05-09 13:24:37 +03:00
|
|
|
"""Alias for `get_sender <telethon.tl.custom.sendergetter.SenderGetter.get_sender>`."""
|
2019-03-26 11:18:18 +03:00
|
|
|
return await self.get_sender()
|
2018-04-08 15:22:11 +03:00
|
|
|
|
|
|
|
@property
|
2018-06-25 12:03:20 +03:00
|
|
|
def input_user(self):
|
2019-05-09 13:24:37 +03:00
|
|
|
"""Alias for `input_sender <telethon.tl.custom.sendergetter.SenderGetter.input_sender>`."""
|
2019-03-26 11:18:18 +03:00
|
|
|
return self.input_sender
|
2018-06-25 12:03:20 +03:00
|
|
|
|
|
|
|
async def get_input_user(self):
|
2019-05-09 13:24:37 +03:00
|
|
|
"""Alias for `get_input_sender <telethon.tl.custom.sendergetter.SenderGetter.get_input_sender>`."""
|
2019-03-26 11:18:18 +03:00
|
|
|
return await self.get_input_sender()
|
2018-04-08 15:22:11 +03:00
|
|
|
|
|
|
|
@property
|
2018-06-25 12:03:20 +03:00
|
|
|
def user_id(self):
|
2019-05-09 13:24:37 +03:00
|
|
|
"""Alias for `sender_id <telethon.tl.custom.sendergetter.SenderGetter.sender_id>`."""
|
2019-03-26 11:18:18 +03:00
|
|
|
return self.sender_id
|