Move /t_ms delta admin text type parsing to separate file and add tests

This commit is contained in:
Mads Marquart
2020-01-20 16:56:35 +01:00
parent 4abe5659ae
commit 0a6bf221e6
4 changed files with 1306 additions and 574 deletions

View File

@@ -16,6 +16,7 @@ from . import (
_event_common,
_client_payload,
_delta_class,
_delta_type,
)
from ._thread import ThreadLocation
@@ -609,244 +610,8 @@ class Client:
"""
def _parse_delta(self, delta):
def get_thread(data):
if "threadFbId" in data["threadKey"]:
group_id = str(data["threadKey"]["threadFbId"])
return Group(session=self.session, id=group_id)
elif "otherUserFbId" in data["threadKey"]:
user_id = str(data["threadKey"]["otherUserFbId"])
return User(session=self.session, id=user_id)
return None
delta_type = delta.get("type")
metadata = delta.get("messageMetadata")
if metadata:
mid = metadata["messageId"]
author_id = str(metadata["actorFbId"])
at = _util.millis_to_datetime(int(metadata.get("timestamp")))
# Color change
if delta_type == "change_thread_theme":
thread = get_thread(metadata)
self.on_color_change(
mid=mid,
author_id=author_id,
new_color=_thread.ThreadABC._parse_color(
delta["untypedData"]["theme_color"]
),
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Emoji change
elif delta_type == "change_thread_icon":
new_emoji = delta["untypedData"]["thread_icon"]
self.on_emoji_change(
mid=mid,
author_id=author_id,
new_emoji=new_emoji,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Nickname change
elif delta_type == "change_thread_nickname":
changed_for = str(delta["untypedData"]["participant_id"])
new_nickname = delta["untypedData"]["nickname"]
self.on_nickname_change(
mid=mid,
author_id=author_id,
changed_for=changed_for,
new_nickname=new_nickname,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Admin added or removed in a group thread
elif delta_type == "change_thread_admins":
target_id = delta["untypedData"]["TARGET_ID"]
admin_event = delta["untypedData"]["ADMIN_EVENT"]
if admin_event == "add_admin":
self.on_admin_added(
mid=mid,
added_id=target_id,
author_id=author_id,
group=get_thread(metadata),
at=at,
)
elif admin_event == "remove_admin":
self.on_admin_removed(
mid=mid,
removed_id=target_id,
author_id=author_id,
group=get_thread(metadata),
at=at,
)
# Group approval mode change
elif delta_type == "change_thread_approval_mode":
approval_mode = bool(int(delta["untypedData"]["APPROVAL_MODE"]))
self.on_approval_mode_change(
mid=mid,
approval_mode=approval_mode,
author_id=author_id,
group=get_thread(metadata),
at=at,
)
# Game played
elif delta_type == "instant_game_update":
game_id = delta["untypedData"]["game_id"]
game_name = delta["untypedData"]["game_name"]
score = delta["untypedData"].get("score")
if score is not None:
score = int(score)
leaderboard = delta["untypedData"].get("leaderboard")
if leaderboard is not None:
leaderboard = _util.parse_json(leaderboard)["scores"]
self.on_game_played(
mid=mid,
author_id=author_id,
game_id=game_id,
game_name=game_name,
score=score,
leaderboard=leaderboard,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Group call started/ended
elif delta_type == "rtc_call_log":
call_status = delta["untypedData"]["event"]
call_duration = _util.seconds_to_timedelta(
int(delta["untypedData"]["call_duration"])
)
is_video_call = bool(int(delta["untypedData"]["is_video_call"]))
if call_status == "call_started":
self.on_call_started(
mid=mid,
caller_id=author_id,
is_video_call=is_video_call,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
elif call_status == "call_ended":
self.on_call_ended(
mid=mid,
caller_id=author_id,
is_video_call=is_video_call,
call_duration=call_duration,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# User joined to group call
elif delta_type == "participant_joined_group_call":
is_video_call = bool(int(delta["untypedData"]["group_call_type"]))
self.on_user_joined_call(
mid=mid,
joined_id=author_id,
is_video_call=is_video_call,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Group poll event
elif delta_type == "group_poll":
event_type = delta["untypedData"]["event_type"]
poll_json = _util.parse_json(delta["untypedData"]["question_json"])
poll = _poll.Poll._from_graphql(self.session, poll_json)
if event_type == "question_creation":
# User created group poll
self.on_poll_created(
mid=mid,
poll=poll,
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
elif event_type == "update_vote":
# User voted on group poll
added = _util.parse_json(delta["untypedData"]["added_option_ids"])
removed = _util.parse_json(delta["untypedData"]["removed_option_ids"])
self.on_poll_voted(
mid=mid,
poll=poll,
added_options=added,
removed_options=removed,
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Plan created
elif delta_type == "lightweight_event_create":
self.on_plan_created(
mid=mid,
plan=PlanData._from_pull(self.session, delta["untypedData"]),
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Plan ended
elif delta_type == "lightweight_event_notify":
self.on_plan_ended(
mid=mid,
plan=PlanData._from_pull(self.session, delta["untypedData"]),
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Plan edited
elif delta_type == "lightweight_event_update":
self.on_plan_edited(
mid=mid,
plan=PlanData._from_pull(self.session, delta["untypedData"]),
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Plan deleted
elif delta_type == "lightweight_event_delete":
self.on_plan_deleted(
mid=mid,
plan=PlanData._from_pull(self.session, delta["untypedData"]),
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Plan participation change
elif delta_type == "lightweight_event_rsvp":
take_part = delta["untypedData"]["guest_status"] == "GOING"
self.on_plan_participation(
mid=mid,
plan=PlanData._from_pull(self.session, delta["untypedData"]),
take_part=take_part,
author_id=author_id,
thread=get_thread(metadata),
at=at,
metadata=metadata,
)
# Client payload (that weird numbers)
elif delta.get("class") == "ClientPayload":
if delta.get("class") == "ClientPayload":
for event in _client_payload.parse_client_payloads(self.session, delta):
self.on_event(event)
@@ -855,6 +620,9 @@ class Client:
if event:
self.on_event(event)
elif delta.get("type"):
self.on_event(_delta_type.parse_delta(self.session, delta))
# Unknown message type
else:
self.on_unknown_messsage_type(msg=delta)
@@ -984,120 +752,6 @@ class Client:
"""Called when the client is listening, and an event happens."""
log.info("Got event: %s", event)
def on_color_change(
self,
mid=None,
author_id=None,
new_color=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody changes a thread's color.
Args:
mid: The action ID
author_id: The ID of the person who changed the color
new_color: The new color. Not limited to the ones in `ThreadABC.set_color`
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("Color change from {} in {}: {}".format(author_id, thread, new_color))
def on_emoji_change(
self,
mid=None,
author_id=None,
new_emoji=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody changes a thread's emoji.
Args:
mid: The action ID
author_id: The ID of the person who changed the emoji
new_emoji: The new emoji
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("Emoji change from {} in {}: {}".format(author_id, thread, new_emoji))
def on_nickname_change(
self,
mid=None,
author_id=None,
changed_for=None,
new_nickname=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody changes a nickname.
Args:
mid: The action ID
author_id: The ID of the person who changed the nickname
changed_for: The ID of the person whom got their nickname changed
new_nickname: The new nickname
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info(
"Nickname change from {} in {} for {}: {}".format(
author_id, thread, changed_for, new_nickname
)
)
def on_admin_added(
self, mid=None, added_id=None, author_id=None, group=None, at=None
):
"""Called when the client is listening, and somebody adds an admin to a group.
Args:
mid: The action ID
added_id: The ID of the admin who got added
author_id: The ID of the person who added the admins
group: Group that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
"""
log.info("{} added admin: {} in {}".format(author_id, added_id, group))
def on_admin_removed(
self, mid=None, removed_id=None, author_id=None, group=None, at=None
):
"""Called when the client is listening, and somebody is removed as an admin in a group.
Args:
mid: The action ID
removed_id: The ID of the admin who got removed
author_id: The ID of the person who removed the admins
group: Group that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
"""
log.info("{} removed admin: {} in {}".format(author_id, removed_id, group))
def on_approval_mode_change(
self, mid=None, approval_mode=None, author_id=None, group=None, at=None,
):
"""Called when the client is listening, and somebody changes approval mode in a group.
Args:
mid: The action ID
approval_mode: True if approval mode is activated
author_id: The ID of the person who changed approval mode
group: Group that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
"""
if approval_mode:
log.info("{} activated approval mode in {}".format(author_id, group))
else:
log.info("{} disabled approval mode in {}".format(author_id, group))
def on_friend_request(self, from_id=None):
"""Called when the client is listening, and somebody sends a friend request.
@@ -1128,229 +782,6 @@ class Client:
"""
pass
def on_game_played(
self,
mid=None,
author_id=None,
game_id=None,
game_name=None,
score=None,
leaderboard=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody plays a game.
Args:
mid: The action ID
author_id: The ID of the person who played the game
game_id: The ID of the game
game_name: Name of the game
score: Score obtained in the game
leaderboard: Actual leader board of the game in the thread
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info('{} played "{}" in {}'.format(author_id, game_name, thread))
def on_call_started(
self,
mid=None,
caller_id=None,
is_video_call=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody starts a call in a group.
Todo:
Make this work with private calls.
Args:
mid: The action ID
caller_id: The ID of the person who started the call
is_video_call: True if it's video call
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} started call in {}".format(caller_id, thread))
def on_call_ended(
self,
mid=None,
caller_id=None,
is_video_call=None,
call_duration=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody ends a call in a group.
Todo:
Make this work with private calls.
Args:
mid: The action ID
caller_id: The ID of the person who ended the call
is_video_call: True if it was video call
call_duration (datetime.timedelta): Call duration
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} ended call in {}".format(caller_id, thread))
def on_user_joined_call(
self,
mid=None,
joined_id=None,
is_video_call=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody joins a group call.
Args:
mid: The action ID
joined_id: The ID of the person who joined the call
is_video_call: True if it's video call
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} joined call in {}".format(joined_id, thread))
def on_poll_created(
self, mid=None, poll=None, author_id=None, thread=None, at=None, metadata=None,
):
"""Called when the client is listening, and somebody creates a group poll.
Args:
mid: The action ID
poll (Poll): Created poll
author_id: The ID of the person who created the poll
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} created poll {} in {}".format(author_id, poll, thread))
def on_poll_voted(
self,
mid=None,
poll=None,
added_options=None,
removed_options=None,
author_id=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody votes in a group poll.
Args:
mid: The action ID
poll (Poll): Poll, that user voted in
author_id: The ID of the person who voted in the poll
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} voted in poll {} in {}".format(author_id, poll, thread))
def on_plan_created(
self, mid=None, plan=None, author_id=None, thread=None, at=None, metadata=None,
):
"""Called when the client is listening, and somebody creates a plan.
Args:
mid: The action ID
plan (Plan): Created plan
author_id: The ID of the person who created the plan
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} created plan {} in {}".format(author_id, plan, thread))
def on_plan_ended(self, mid=None, plan=None, thread=None, at=None, metadata=None):
"""Called when the client is listening, and a plan ends.
Args:
mid: The action ID
plan (Plan): Ended plan
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("Plan {} has ended in {}".format(plan, thread))
def on_plan_edited(
self, mid=None, plan=None, author_id=None, thread=None, at=None, metadata=None,
):
"""Called when the client is listening, and somebody edits a plan.
Args:
mid: The action ID
plan (Plan): Edited plan
author_id: The ID of the person who edited the plan
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} edited plan {} in {}".format(author_id, plan, thread))
def on_plan_deleted(
self, mid=None, plan=None, author_id=None, thread=None, at=None, metadata=None,
):
"""Called when the client is listening, and somebody deletes a plan.
Args:
mid: The action ID
plan (Plan): Deleted plan
author_id: The ID of the person who deleted the plan
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
log.info("{} deleted plan {} in {}".format(author_id, plan, thread))
def on_plan_participation(
self,
mid=None,
plan=None,
take_part=None,
author_id=None,
thread=None,
at=None,
metadata=None,
):
"""Called when the client is listening, and somebody takes part in a plan or not.
Args:
mid: The action ID
plan (Plan): Plan
take_part (bool): Whether the person takes part in the plan or not
author_id: The ID of the person who will participate in the plan or not
thread: Thread that the action was sent to. See :ref:`intro_threads`
at (datetime.datetime): When the action was executed
metadata: Extra metadata about the action
"""
if take_part:
log.info(
"{} will take part in {} in {} ({})".format(author_id, plan, thread)
)
else:
log.info(
"{} won't take part in {} in {} ({})".format(author_id, plan, thread)
)
def on_chat_timestamp(self, buddylist=None):
"""Called when the client receives chat online presence update.