Move /t_ms delta admin text type parsing to separate file and add tests
This commit is contained in:
@@ -59,6 +59,24 @@ from ._delta_class import (
|
|||||||
ThreadsRead,
|
ThreadsRead,
|
||||||
MessageEvent,
|
MessageEvent,
|
||||||
)
|
)
|
||||||
|
from ._delta_type import (
|
||||||
|
ColorSet,
|
||||||
|
EmojiSet,
|
||||||
|
NicknameSet,
|
||||||
|
AdminsAdded,
|
||||||
|
AdminsRemoved,
|
||||||
|
ApprovalModeSet,
|
||||||
|
CallStarted,
|
||||||
|
CallEnded,
|
||||||
|
CallJoined,
|
||||||
|
PollCreated,
|
||||||
|
PollVoted,
|
||||||
|
PlanCreated,
|
||||||
|
PlanEnded,
|
||||||
|
PlanEdited,
|
||||||
|
PlanDeleted,
|
||||||
|
PlanResponded,
|
||||||
|
)
|
||||||
|
|
||||||
from ._client import Client
|
from ._client import Client
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@ from . import (
|
|||||||
_event_common,
|
_event_common,
|
||||||
_client_payload,
|
_client_payload,
|
||||||
_delta_class,
|
_delta_class,
|
||||||
|
_delta_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ._thread import ThreadLocation
|
from ._thread import ThreadLocation
|
||||||
@@ -609,244 +610,8 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _parse_delta(self, delta):
|
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)
|
# 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):
|
for event in _client_payload.parse_client_payloads(self.session, delta):
|
||||||
self.on_event(event)
|
self.on_event(event)
|
||||||
|
|
||||||
@@ -855,6 +620,9 @@ class Client:
|
|||||||
if event:
|
if event:
|
||||||
self.on_event(event)
|
self.on_event(event)
|
||||||
|
|
||||||
|
elif delta.get("type"):
|
||||||
|
self.on_event(_delta_type.parse_delta(self.session, delta))
|
||||||
|
|
||||||
# Unknown message type
|
# Unknown message type
|
||||||
else:
|
else:
|
||||||
self.on_unknown_messsage_type(msg=delta)
|
self.on_unknown_messsage_type(msg=delta)
|
||||||
@@ -984,120 +752,6 @@ class Client:
|
|||||||
"""Called when the client is listening, and an event happens."""
|
"""Called when the client is listening, and an event happens."""
|
||||||
log.info("Got event: %s", event)
|
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):
|
def on_friend_request(self, from_id=None):
|
||||||
"""Called when the client is listening, and somebody sends a friend request.
|
"""Called when the client is listening, and somebody sends a friend request.
|
||||||
|
|
||||||
@@ -1128,229 +782,6 @@ class Client:
|
|||||||
"""
|
"""
|
||||||
pass
|
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):
|
def on_chat_timestamp(self, buddylist=None):
|
||||||
"""Called when the client receives chat online presence update.
|
"""Called when the client receives chat online presence update.
|
||||||
|
|
||||||
|
329
fbchat/_delta_type.py
Normal file
329
fbchat/_delta_type.py
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
import attr
|
||||||
|
import datetime
|
||||||
|
from ._event_common import attrs_event, Event, UnknownEvent, ThreadEvent
|
||||||
|
from . import _util, _user, _thread, _poll, _plan
|
||||||
|
|
||||||
|
from typing import Sequence, Optional
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class ColorSet(ThreadEvent):
|
||||||
|
"""Somebody set the color in a thread."""
|
||||||
|
|
||||||
|
#: The new color. Not limited to the ones in `ThreadABC.set_color`
|
||||||
|
color = attr.ib(type=str)
|
||||||
|
#: When the color was set
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
color = _thread.ThreadABC._parse_color(data["untypedData"]["theme_color"])
|
||||||
|
return cls(author=author, thread=thread, color=color, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class EmojiSet(ThreadEvent):
|
||||||
|
"""Somebody set the emoji in a thread."""
|
||||||
|
|
||||||
|
#: The new emoji
|
||||||
|
emoji = attr.ib(type=str)
|
||||||
|
#: When the emoji was set
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
emoji = data["untypedData"]["thread_icon"]
|
||||||
|
return cls(author=author, thread=thread, emoji=emoji, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class NicknameSet(ThreadEvent):
|
||||||
|
"""Somebody set the nickname of a person in a thread."""
|
||||||
|
|
||||||
|
#: The person whose nickname was set
|
||||||
|
subject = attr.ib(type=str)
|
||||||
|
#: The new nickname. If ``None``, the nickname was cleared
|
||||||
|
nickname = attr.ib(type=Optional[str])
|
||||||
|
#: When the nickname was set
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
subject = _user.User(session=session, id=data["untypedData"]["participant_id"])
|
||||||
|
nickname = data["untypedData"]["nickname"] or None # None if ""
|
||||||
|
return cls(
|
||||||
|
author=author, thread=thread, subject=subject, nickname=nickname, at=at
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class AdminsAdded(ThreadEvent):
|
||||||
|
"""Somebody added admins to a group."""
|
||||||
|
|
||||||
|
#: The people that were set as admins
|
||||||
|
added = attr.ib(type=Sequence[_user.User])
|
||||||
|
#: When the admins were added
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
subject = _user.User(session=session, id=data["untypedData"]["TARGET_ID"])
|
||||||
|
return cls(author=author, thread=thread, added=[subject], at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class AdminsRemoved(ThreadEvent):
|
||||||
|
"""Somebody removed admins from a group."""
|
||||||
|
|
||||||
|
#: The people that were removed as admins
|
||||||
|
removed = attr.ib(type=Sequence[_user.User])
|
||||||
|
#: When the admins were removed
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
subject = _user.User(session=session, id=data["untypedData"]["TARGET_ID"])
|
||||||
|
return cls(author=author, thread=thread, removed=[subject], at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class ApprovalModeSet(ThreadEvent):
|
||||||
|
"""Somebody changed the approval mode in a group."""
|
||||||
|
|
||||||
|
require_admin_approval = attr.ib(type=bool)
|
||||||
|
#: When the approval mode was set
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
raa = data["untypedData"]["APPROVAL_MODE"] == "1"
|
||||||
|
return cls(author=author, thread=thread, require_admin_approval=raa, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class CallStarted(ThreadEvent):
|
||||||
|
"""Somebody started a call."""
|
||||||
|
|
||||||
|
#: When the call was started
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
return cls(author=author, thread=thread, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class CallEnded(ThreadEvent):
|
||||||
|
"""Somebody ended a call."""
|
||||||
|
|
||||||
|
#: How long the call took
|
||||||
|
duration = attr.ib(type=datetime.timedelta)
|
||||||
|
#: When the call ended
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
duration = _util.seconds_to_timedelta(int(data["untypedData"]["call_duration"]))
|
||||||
|
return cls(author=author, thread=thread, duration=duration, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class CallJoined(ThreadEvent):
|
||||||
|
"""Somebody joined a call."""
|
||||||
|
|
||||||
|
#: When the call ended
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
return cls(author=author, thread=thread, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PollCreated(ThreadEvent):
|
||||||
|
"""Somebody created a group poll."""
|
||||||
|
|
||||||
|
#: The new poll
|
||||||
|
poll = attr.ib(type=_poll.Poll)
|
||||||
|
#: When the poll was created
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
poll_data = _util.parse_json(data["untypedData"]["question_json"])
|
||||||
|
poll = _poll.Poll._from_graphql(session, poll_data)
|
||||||
|
return cls(author=author, thread=thread, poll=poll, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PollVoted(ThreadEvent):
|
||||||
|
"""Somebody voted in a group poll."""
|
||||||
|
|
||||||
|
#: The updated poll
|
||||||
|
poll = attr.ib(type=_poll.Poll)
|
||||||
|
#: Ids of the voted options
|
||||||
|
added_ids = attr.ib(type=Sequence[str])
|
||||||
|
#: Ids of the un-voted options
|
||||||
|
removed_ids = attr.ib(type=Sequence[str])
|
||||||
|
#: When the poll was voted in
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
poll_data = _util.parse_json(data["untypedData"]["question_json"])
|
||||||
|
poll = _poll.Poll._from_graphql(session, poll_data)
|
||||||
|
added_ids = _util.parse_json(data["untypedData"]["added_option_ids"])
|
||||||
|
removed_ids = _util.parse_json(data["untypedData"]["removed_option_ids"])
|
||||||
|
return cls(
|
||||||
|
author=author,
|
||||||
|
thread=thread,
|
||||||
|
poll=poll,
|
||||||
|
added_ids=[str(x) for x in added_ids],
|
||||||
|
removed_ids=[str(x) for x in removed_ids],
|
||||||
|
at=at,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PlanCreated(ThreadEvent):
|
||||||
|
"""Somebody created a plan in a group."""
|
||||||
|
|
||||||
|
#: The new plan
|
||||||
|
plan = attr.ib(type=_plan.PlanData)
|
||||||
|
#: When the plan was created
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
plan = _plan.PlanData._from_pull(session, data["untypedData"])
|
||||||
|
return cls(author=author, thread=thread, plan=plan, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PlanEnded(ThreadEvent):
|
||||||
|
"""A plan ended."""
|
||||||
|
|
||||||
|
#: The ended plan
|
||||||
|
plan = attr.ib(type=_plan.PlanData)
|
||||||
|
#: When the plan ended
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
plan = _plan.PlanData._from_pull(session, data["untypedData"])
|
||||||
|
return cls(author=author, thread=thread, plan=plan, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PlanEdited(ThreadEvent):
|
||||||
|
"""Somebody changed a plan in a group."""
|
||||||
|
|
||||||
|
#: The updated plan
|
||||||
|
plan = attr.ib(type=_plan.PlanData)
|
||||||
|
#: When the plan was updated
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
plan = _plan.PlanData._from_pull(session, data["untypedData"])
|
||||||
|
return cls(author=author, thread=thread, plan=plan, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PlanDeleted(ThreadEvent):
|
||||||
|
"""Somebody removed a plan in a group."""
|
||||||
|
|
||||||
|
#: The removed plan
|
||||||
|
plan = attr.ib(type=_plan.PlanData)
|
||||||
|
#: When the plan was removed
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
plan = _plan.PlanData._from_pull(session, data["untypedData"])
|
||||||
|
return cls(author=author, thread=thread, plan=plan, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
@attrs_event
|
||||||
|
class PlanResponded(ThreadEvent):
|
||||||
|
"""Somebody responded to a plan in a group."""
|
||||||
|
|
||||||
|
#: The plan that was responded to
|
||||||
|
plan = attr.ib(type=_plan.PlanData)
|
||||||
|
#: Whether the author will go to the plan or not
|
||||||
|
take_part = attr.ib(type=bool)
|
||||||
|
#: When the plan was removed
|
||||||
|
at = attr.ib(type=datetime.datetime)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse(cls, session, data):
|
||||||
|
author, thread, at = cls._parse_metadata(session, data)
|
||||||
|
plan = _plan.PlanData._from_pull(session, data["untypedData"])
|
||||||
|
take_part = data["untypedData"]["guest_status"] == "GOING"
|
||||||
|
return cls(author=author, thread=thread, plan=plan, take_part=take_part, at=at)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_delta(session, data):
|
||||||
|
type_ = data.get("type")
|
||||||
|
if type_ == "change_thread_theme":
|
||||||
|
return ColorSet._parse(session, data)
|
||||||
|
elif type_ == "change_thread_icon":
|
||||||
|
return EmojiSet._parse(session, data)
|
||||||
|
elif type_ == "change_thread_nickname":
|
||||||
|
return NicknameSet._parse(session, data)
|
||||||
|
elif type_ == "change_thread_admins":
|
||||||
|
event_type = data["untypedData"]["ADMIN_EVENT"]
|
||||||
|
if event_type == "add_admin":
|
||||||
|
return AdminsAdded._parse(session, data)
|
||||||
|
elif event_type == "remove_admin":
|
||||||
|
return AdminsRemoved._parse(session, data)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif type_ == "change_thread_approval_mode":
|
||||||
|
return ApprovalModeSet._parse(session, data)
|
||||||
|
elif type_ == "instant_game_update":
|
||||||
|
pass # TODO: This
|
||||||
|
elif type_ == "messenger_call_log": # Previously "rtc_call_log"
|
||||||
|
event_type = data["untypedData"]["event"]
|
||||||
|
if event_type == "group_call_started":
|
||||||
|
return CallStarted._parse(session, data)
|
||||||
|
elif event_type in ["group_call_ended", "one_on_one_call_ended"]:
|
||||||
|
return CallEnded._parse(session, data)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif type_ == "participant_joined_group_call":
|
||||||
|
return CallJoined._parse(session, data)
|
||||||
|
elif type_ == "group_poll":
|
||||||
|
event_type = data["untypedData"]["event_type"]
|
||||||
|
if event_type == "question_creation":
|
||||||
|
return PollCreated._parse(session, data)
|
||||||
|
elif event_type == "update_vote":
|
||||||
|
return PollVoted._parse(session, data)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
elif type_ == "lightweight_event_create":
|
||||||
|
return PlanCreated._parse(session, data)
|
||||||
|
elif type_ == "lightweight_event_notify":
|
||||||
|
return PlanEnded._parse(session, data)
|
||||||
|
elif type_ == "lightweight_event_update":
|
||||||
|
return PlanEdited._parse(session, data)
|
||||||
|
elif type_ == "lightweight_event_delete":
|
||||||
|
return PlanDeleted._parse(session, data)
|
||||||
|
elif type_ == "lightweight_event_rsvp":
|
||||||
|
return PlanResponded._parse(session, data)
|
||||||
|
return UnknownEvent(data=data)
|
954
tests/test_delta_type.py
Normal file
954
tests/test_delta_type.py
Normal file
@@ -0,0 +1,954 @@
|
|||||||
|
import datetime
|
||||||
|
import pytest
|
||||||
|
from fbchat import (
|
||||||
|
_util,
|
||||||
|
ParseError,
|
||||||
|
User,
|
||||||
|
Group,
|
||||||
|
Poll,
|
||||||
|
PollOption,
|
||||||
|
PlanData,
|
||||||
|
GuestStatus,
|
||||||
|
UnknownEvent,
|
||||||
|
ColorSet,
|
||||||
|
EmojiSet,
|
||||||
|
NicknameSet,
|
||||||
|
AdminsAdded,
|
||||||
|
AdminsRemoved,
|
||||||
|
ApprovalModeSet,
|
||||||
|
CallStarted,
|
||||||
|
CallEnded,
|
||||||
|
CallJoined,
|
||||||
|
PollCreated,
|
||||||
|
PollVoted,
|
||||||
|
PlanCreated,
|
||||||
|
PlanEnded,
|
||||||
|
PlanEdited,
|
||||||
|
PlanDeleted,
|
||||||
|
PlanResponded,
|
||||||
|
)
|
||||||
|
from fbchat._message import Message, MessageData
|
||||||
|
from fbchat._delta_type import parse_delta
|
||||||
|
|
||||||
|
|
||||||
|
def test_color_set(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You changed the chat theme to Orange.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_theme",
|
||||||
|
"untypedData": {
|
||||||
|
"should_show_icon": "1",
|
||||||
|
"theme_color": "FFFF7E29",
|
||||||
|
"accessibility_label": "Orange",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert ColorSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
color="#ff7e29",
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_emoji_set(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You set the emoji to 🌟.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"skipSnippetUpdate": False,
|
||||||
|
"tags": ["source:generic_admin_text"],
|
||||||
|
"threadKey": {"otherUserFbId": "1234"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"type": "change_thread_icon",
|
||||||
|
"untypedData": {
|
||||||
|
"thread_icon_url": "https://www.facebook.com/images/emoji.php/v9/te0/1/16/1f31f.png",
|
||||||
|
"thread_icon": "🌟",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert EmojiSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=User(session=session, id="1234"),
|
||||||
|
emoji="🌟",
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_nickname_set(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You set the nickname for Abc Def to abc.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_nickname",
|
||||||
|
"untypedData": {"nickname": "abc", "participant_id": "2345"},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert NicknameSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
subject=User(session=session, id="2345"),
|
||||||
|
nickname="abc",
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_nickname_clear(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You cleared your nickname.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"skipSnippetUpdate": False,
|
||||||
|
"tags": ["source:generic_admin_text"],
|
||||||
|
"threadKey": {"otherUserFbId": "1234"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"type": "change_thread_nickname",
|
||||||
|
"untypedData": {"nickname": "", "participant_id": "1234"},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert NicknameSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=User(session=session, id="1234"),
|
||||||
|
subject=User(session=session, id="1234"),
|
||||||
|
nickname=None,
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_admins_added(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You added Abc Def as a group admin.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": True,
|
||||||
|
"tags": ["source:titan:web"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_admins",
|
||||||
|
"untypedData": {
|
||||||
|
"THREAD_CATEGORY": "GROUP",
|
||||||
|
"TARGET_ID": "2345",
|
||||||
|
"ADMIN_TYPE": "0",
|
||||||
|
"ADMIN_EVENT": "add_admin",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert AdminsAdded(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
added=[User(session=session, id="2345")],
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_admins_removed(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You removed yourself as a group admin.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": True,
|
||||||
|
"tags": ["source:titan:web"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_admins",
|
||||||
|
"untypedData": {
|
||||||
|
"THREAD_CATEGORY": "GROUP",
|
||||||
|
"TARGET_ID": "1234",
|
||||||
|
"ADMIN_TYPE": "0",
|
||||||
|
"ADMIN_EVENT": "remove_admin",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert AdminsRemoved(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
removed=[User(session=session, id="1234")],
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_approvalmode_set(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You turned on member approval and will review requests to join the group.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": True,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_approval_mode",
|
||||||
|
"untypedData": {"APPROVAL_MODE": "1", "THREAD_CATEGORY": "GROUP"},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert ApprovalModeSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
require_admin_approval=True,
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_approvalmode_unset(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You turned off member approval. Anyone with the link can join the group.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": True,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "change_thread_approval_mode",
|
||||||
|
"untypedData": {"APPROVAL_MODE": "0", "THREAD_CATEGORY": "GROUP"},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert ApprovalModeSet(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
require_admin_approval=False,
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_call_started(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You started a call.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "messenger_call_log",
|
||||||
|
"untypedData": {
|
||||||
|
"call_capture_attachments": "",
|
||||||
|
"caller_id": "1234",
|
||||||
|
"conference_name": "MESSENGER:134845267536444",
|
||||||
|
"rating": "",
|
||||||
|
"messenger_call_instance_id": "0",
|
||||||
|
"video": "",
|
||||||
|
"event": "group_call_started",
|
||||||
|
"server_info": "XYZ123ABC",
|
||||||
|
"call_duration": "0",
|
||||||
|
"callee_id": "0",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
data2 = {
|
||||||
|
"callState": "AUDIO_GROUP_CALL",
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": [],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
},
|
||||||
|
"serverInfoData": "XYZ123ABC",
|
||||||
|
"class": "RtcCallData",
|
||||||
|
}
|
||||||
|
assert CallStarted(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_group_call_ended(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "The call ended.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "messenger_call_log",
|
||||||
|
"untypedData": {
|
||||||
|
"call_capture_attachments": "",
|
||||||
|
"caller_id": "1234",
|
||||||
|
"conference_name": "MESSENGER:1234567890",
|
||||||
|
"rating": "0",
|
||||||
|
"messenger_call_instance_id": "1234567890",
|
||||||
|
"video": "",
|
||||||
|
"event": "group_call_ended",
|
||||||
|
"server_info": "XYZ123ABC",
|
||||||
|
"call_duration": "31",
|
||||||
|
"callee_id": "0",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
data2 = {
|
||||||
|
"callState": "NO_ONGOING_CALL",
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": [],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
},
|
||||||
|
"class": "RtcCallData",
|
||||||
|
}
|
||||||
|
assert CallEnded(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
duration=datetime.timedelta(seconds=31),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_user_call_ended(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "Abc called you.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"skipSnippetUpdate": False,
|
||||||
|
"tags": ["source:generic_admin_text", "no_push"],
|
||||||
|
"threadKey": {"otherUserFbId": "1234"},
|
||||||
|
"threadReadStateEffect": "KEEP_AS_IS",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"type": "messenger_call_log",
|
||||||
|
"untypedData": {
|
||||||
|
"call_capture_attachments": "",
|
||||||
|
"caller_id": "1234",
|
||||||
|
"conference_name": "MESSENGER:1234567890",
|
||||||
|
"rating": "0",
|
||||||
|
"messenger_call_instance_id": "1234567890",
|
||||||
|
"video": "",
|
||||||
|
"event": "one_on_one_call_ended",
|
||||||
|
"server_info": "",
|
||||||
|
"call_duration": "3",
|
||||||
|
"callee_id": "100002950119740",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert CallEnded(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=User(session=session, id="1234"),
|
||||||
|
duration=datetime.timedelta(seconds=3),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_call_joined(session):
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "Abc joined the call.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "participant_joined_group_call",
|
||||||
|
"untypedData": {
|
||||||
|
"server_info_data": "XYZ123ABC",
|
||||||
|
"group_call_type": "0",
|
||||||
|
"joining_user": "2345",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert CallJoined(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_poll_created(session):
|
||||||
|
poll_data = {
|
||||||
|
"id": "112233",
|
||||||
|
"text": "A poll",
|
||||||
|
"total_count": 2,
|
||||||
|
"viewer_has_voted": "true",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"id": "1001",
|
||||||
|
"text": "Option A",
|
||||||
|
"total_count": 1,
|
||||||
|
"viewer_has_voted": "true",
|
||||||
|
"voters": ["1234"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1002",
|
||||||
|
"text": "Option B",
|
||||||
|
"total_count": 0,
|
||||||
|
"viewer_has_voted": "false",
|
||||||
|
"voters": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You created a poll: A poll.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "group_poll",
|
||||||
|
"untypedData": {
|
||||||
|
"added_option_ids": "[]",
|
||||||
|
"removed_option_ids": "[]",
|
||||||
|
"question_json": _util.json_minimal(poll_data),
|
||||||
|
"event_type": "question_creation",
|
||||||
|
"question_id": "112233",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PollCreated(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
poll=Poll(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
question="A poll",
|
||||||
|
options=[
|
||||||
|
PollOption(
|
||||||
|
id="1001",
|
||||||
|
text="Option A",
|
||||||
|
vote=True,
|
||||||
|
voters=["1234"],
|
||||||
|
votes_count=1,
|
||||||
|
),
|
||||||
|
PollOption(
|
||||||
|
id="1002", text="Option B", vote=False, voters=[], votes_count=0
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options_count=2,
|
||||||
|
),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_poll_answered(session):
|
||||||
|
poll_data = {
|
||||||
|
"id": "112233",
|
||||||
|
"text": "A poll",
|
||||||
|
"total_count": 3,
|
||||||
|
"viewer_has_voted": "true",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"id": "1002",
|
||||||
|
"text": "Option B",
|
||||||
|
"total_count": 2,
|
||||||
|
"viewer_has_voted": "true",
|
||||||
|
"voters": ["1234", "2345"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1003",
|
||||||
|
"text": "Option C",
|
||||||
|
"total_count": 1,
|
||||||
|
"viewer_has_voted": "true",
|
||||||
|
"voters": ["1234"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1001",
|
||||||
|
"text": "Option A",
|
||||||
|
"total_count": 0,
|
||||||
|
"viewer_has_voted": "false",
|
||||||
|
"voters": [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": 'You changed your vote to "Option B" and 1 other option in the poll: A poll.',
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "group_poll",
|
||||||
|
"untypedData": {
|
||||||
|
"added_option_ids": "[1002,1003]",
|
||||||
|
"removed_option_ids": "[1001]",
|
||||||
|
"question_json": _util.json_minimal(poll_data),
|
||||||
|
"event_type": "update_vote",
|
||||||
|
"question_id": "112233",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PollVoted(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
poll=Poll(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
question="A poll",
|
||||||
|
options=[
|
||||||
|
PollOption(
|
||||||
|
id="1002",
|
||||||
|
text="Option B",
|
||||||
|
vote=True,
|
||||||
|
voters=["1234", "2345"],
|
||||||
|
votes_count=2,
|
||||||
|
),
|
||||||
|
PollOption(
|
||||||
|
id="1003",
|
||||||
|
text="Option C",
|
||||||
|
vote=True,
|
||||||
|
voters=["1234"],
|
||||||
|
votes_count=1,
|
||||||
|
),
|
||||||
|
PollOption(
|
||||||
|
id="1001", text="Option A", vote=False, voters=[], votes_count=0
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options_count=3,
|
||||||
|
),
|
||||||
|
added_ids=["1002", "1003"],
|
||||||
|
removed_ids=["1001"],
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_plan_created(session):
|
||||||
|
guest_list = [
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "3456"}},
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "2345"}},
|
||||||
|
{"guest_list_state": "GOING", "node": {"id": "1234"}},
|
||||||
|
]
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You created a plan.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "lightweight_event_create",
|
||||||
|
"untypedData": {
|
||||||
|
"event_timezone": "",
|
||||||
|
"event_creator_id": "1234",
|
||||||
|
"event_id": "112233",
|
||||||
|
"event_type": "EVENT",
|
||||||
|
"event_track_rsvp": "1",
|
||||||
|
"event_title": "A plan",
|
||||||
|
"event_time": "1600000000",
|
||||||
|
"event_seconds_to_notify_before": "3600",
|
||||||
|
"guest_state_list": _util.json_minimal(guest_list),
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PlanCreated(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
plan=PlanData(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
time=datetime.datetime(
|
||||||
|
2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc
|
||||||
|
),
|
||||||
|
title="A plan",
|
||||||
|
author_id="1234",
|
||||||
|
guests={
|
||||||
|
"1234": GuestStatus.GOING,
|
||||||
|
"2345": GuestStatus.INVITED,
|
||||||
|
"3456": GuestStatus.INVITED,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="Need to gather test data")
|
||||||
|
def test_plan_ended(session):
|
||||||
|
data = {}
|
||||||
|
assert PlanEnded(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
plan=PlanData(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
time=datetime.datetime(
|
||||||
|
2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc
|
||||||
|
),
|
||||||
|
title="A plan",
|
||||||
|
author_id="1234",
|
||||||
|
guests={
|
||||||
|
"1234": GuestStatus.GOING,
|
||||||
|
"2345": GuestStatus.INVITED,
|
||||||
|
"3456": GuestStatus.INVITED,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_plan_edited(session):
|
||||||
|
guest_list = [
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "3456"}},
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "2345"}},
|
||||||
|
{"guest_list_state": "GOING", "node": {"id": "1234"}},
|
||||||
|
]
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You named the plan A plan.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "lightweight_event_update",
|
||||||
|
"untypedData": {
|
||||||
|
"event_creator_id": "1234",
|
||||||
|
"latitude": "0",
|
||||||
|
"event_title": "A plan",
|
||||||
|
"event_seconds_to_notify_before": "3600",
|
||||||
|
"guest_state_list": _util.json_minimal(guest_list),
|
||||||
|
"event_end_time": "0",
|
||||||
|
"event_timezone": "",
|
||||||
|
"event_id": "112233",
|
||||||
|
"event_type": "EVENT",
|
||||||
|
"event_location_id": "2233445566",
|
||||||
|
"event_location_name": "",
|
||||||
|
"event_time": "1600000000",
|
||||||
|
"event_note": "",
|
||||||
|
"longitude": "0",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PlanEdited(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
plan=PlanData(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
time=datetime.datetime(
|
||||||
|
2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc
|
||||||
|
),
|
||||||
|
title="A plan",
|
||||||
|
location_id="2233445566",
|
||||||
|
author_id="1234",
|
||||||
|
guests={
|
||||||
|
"1234": GuestStatus.GOING,
|
||||||
|
"2345": GuestStatus.INVITED,
|
||||||
|
"3456": GuestStatus.INVITED,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_plan_deleted(session):
|
||||||
|
guest_list = [
|
||||||
|
{"guest_list_state": "GOING", "node": {"id": "1234"}},
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "3456"}},
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "2345"}},
|
||||||
|
]
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You deleted the plan A plan for Mon, 20 Jan at 15:30.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "lightweight_event_delete",
|
||||||
|
"untypedData": {
|
||||||
|
"event_end_time": "0",
|
||||||
|
"event_timezone": "",
|
||||||
|
"event_id": "112233",
|
||||||
|
"event_type": "EVENT",
|
||||||
|
"event_location_id": "2233445566",
|
||||||
|
"latitude": "0",
|
||||||
|
"event_title": "A plan",
|
||||||
|
"event_time": "1600000000",
|
||||||
|
"event_seconds_to_notify_before": "3600",
|
||||||
|
"guest_state_list": _util.json_minimal(guest_list),
|
||||||
|
"event_note": "",
|
||||||
|
"longitude": "0",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PlanDeleted(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
plan=PlanData(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
time=datetime.datetime(
|
||||||
|
2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc
|
||||||
|
),
|
||||||
|
title="A plan",
|
||||||
|
location_id="2233445566",
|
||||||
|
author_id=None,
|
||||||
|
guests={
|
||||||
|
"1234": GuestStatus.GOING,
|
||||||
|
"2345": GuestStatus.INVITED,
|
||||||
|
"3456": GuestStatus.INVITED,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_plan_participation(session):
|
||||||
|
guest_list = [
|
||||||
|
{"guest_list_state": "DECLINED", "node": {"id": "1234"}},
|
||||||
|
{"guest_list_state": "GOING", "node": {"id": "2345"}},
|
||||||
|
{"guest_list_state": "INVITED", "node": {"id": "3456"}},
|
||||||
|
]
|
||||||
|
data = {
|
||||||
|
"irisSeqId": "1111111",
|
||||||
|
"irisTags": ["DeltaAdminTextMessage", "is_from_iris_fanout"],
|
||||||
|
"messageMetadata": {
|
||||||
|
"actorFbId": "1234",
|
||||||
|
"adminText": "You responded Can't Go to def.",
|
||||||
|
"folderId": {"systemFolderId": "INBOX"},
|
||||||
|
"messageId": "mid.$XYZ",
|
||||||
|
"offlineThreadingId": "11223344556677889900",
|
||||||
|
"skipBumpThread": False,
|
||||||
|
"tags": ["source:titan:web", "no_push"],
|
||||||
|
"threadKey": {"threadFbId": "4321"},
|
||||||
|
"threadReadStateEffect": "MARK_UNREAD",
|
||||||
|
"timestamp": "1500000000000",
|
||||||
|
"unsendType": "deny_log_message",
|
||||||
|
},
|
||||||
|
"participants": ["1234", "2345", "3456"],
|
||||||
|
"requestContext": {"apiArgs": {}},
|
||||||
|
"tqSeqId": "1111",
|
||||||
|
"type": "lightweight_event_rsvp",
|
||||||
|
"untypedData": {
|
||||||
|
"event_creator_id": "2345",
|
||||||
|
"guest_status": "DECLINED",
|
||||||
|
"latitude": "0",
|
||||||
|
"event_track_rsvp": "1",
|
||||||
|
"event_title": "A plan",
|
||||||
|
"event_seconds_to_notify_before": "3600",
|
||||||
|
"guest_state_list": _util.json_minimal(guest_list),
|
||||||
|
"event_end_time": "0",
|
||||||
|
"event_timezone": "",
|
||||||
|
"event_id": "112233",
|
||||||
|
"event_type": "EVENT",
|
||||||
|
"guest_id": "1234",
|
||||||
|
"event_location_id": "2233445566",
|
||||||
|
"event_time": "1600000000",
|
||||||
|
"event_note": "",
|
||||||
|
"longitude": "0",
|
||||||
|
},
|
||||||
|
"class": "AdminTextMessage",
|
||||||
|
}
|
||||||
|
assert PlanResponded(
|
||||||
|
author=User(session=session, id="1234"),
|
||||||
|
thread=Group(session=session, id="4321"),
|
||||||
|
plan=PlanData(
|
||||||
|
session=session,
|
||||||
|
id="112233",
|
||||||
|
time=datetime.datetime(
|
||||||
|
2020, 9, 13, 12, 26, 40, tzinfo=datetime.timezone.utc
|
||||||
|
),
|
||||||
|
title="A plan",
|
||||||
|
location_id="2233445566",
|
||||||
|
author_id="2345",
|
||||||
|
guests={
|
||||||
|
"1234": GuestStatus.DECLINED,
|
||||||
|
"2345": GuestStatus.GOING,
|
||||||
|
"3456": GuestStatus.INVITED,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
take_part=False,
|
||||||
|
at=datetime.datetime(2017, 7, 14, 2, 40, tzinfo=datetime.timezone.utc),
|
||||||
|
) == parse_delta(session, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_delta_unknown(session):
|
||||||
|
assert UnknownEvent(data={"abc": 10}) == parse_delta(session, {"abc": 10})
|
Reference in New Issue
Block a user