diff --git a/fbchat/_client.py b/fbchat/_client.py index df406e7..f6e4b6b 100644 --- a/fbchat/_client.py +++ b/fbchat/_client.py @@ -1261,8 +1261,7 @@ class Client(object): """ data = {"event_reminder_id": plan_id} j = self._post(self.req_url.PLAN_INFO, data, fix_request=True, as_json=True) - plan = graphql_to_plan(j["payload"]) - return plan + return Plan._from_fetch(j["payload"]) def _getPrivateData(self): j = self.graphql_request(GraphQL(doc_id="1868889766468115")) @@ -2869,10 +2868,9 @@ class Client(object): # Plan created elif delta_type == "lightweight_event_create": thread_id, thread_type = getThreadIdAndThreadType(metadata) - plan = graphql_to_plan(delta["untypedData"]) self.onPlanCreated( mid=mid, - plan=plan, + plan=Plan._from_pull(delta["untypedData"]), author_id=author_id, thread_id=thread_id, thread_type=thread_type, @@ -2884,10 +2882,9 @@ class Client(object): # Plan ended elif delta_type == "lightweight_event_notify": thread_id, thread_type = getThreadIdAndThreadType(metadata) - plan = graphql_to_plan(delta["untypedData"]) self.onPlanEnded( mid=mid, - plan=plan, + plan=Plan._from_pull(delta["untypedData"]), thread_id=thread_id, thread_type=thread_type, ts=ts, @@ -2898,10 +2895,9 @@ class Client(object): # Plan edited elif delta_type == "lightweight_event_update": thread_id, thread_type = getThreadIdAndThreadType(metadata) - plan = graphql_to_plan(delta["untypedData"]) self.onPlanEdited( mid=mid, - plan=plan, + plan=Plan._from_pull(delta["untypedData"]), author_id=author_id, thread_id=thread_id, thread_type=thread_type, @@ -2913,10 +2909,9 @@ class Client(object): # Plan deleted elif delta_type == "lightweight_event_delete": thread_id, thread_type = getThreadIdAndThreadType(metadata) - plan = graphql_to_plan(delta["untypedData"]) self.onPlanDeleted( mid=mid, - plan=plan, + plan=Plan._from_pull(delta["untypedData"]), author_id=author_id, thread_id=thread_id, thread_type=thread_type, @@ -2928,11 +2923,10 @@ class Client(object): # Plan participation change elif delta_type == "lightweight_event_rsvp": thread_id, thread_type = getThreadIdAndThreadType(metadata) - plan = graphql_to_plan(delta["untypedData"]) take_part = delta["untypedData"]["guest_status"] == "GOING" self.onPlanParticipation( mid=mid, - plan=plan, + plan=Plan._from_pull(delta["untypedData"]), take_part=take_part, author_id=author_id, thread_id=thread_id, diff --git a/fbchat/_graphql.py b/fbchat/_graphql.py index 932c5c8..a483c0e 100644 --- a/fbchat/_graphql.py +++ b/fbchat/_graphql.py @@ -106,57 +106,6 @@ def graphql_to_subattachment(a): ) -def graphql_to_plan(a): - if a.get("event_members"): - rtn = Plan( - time=a.get("event_time"), - title=a.get("title"), - location=a.get("location_name"), - ) - if a.get("location_id") != 0: - rtn.location_id = str(a.get("location_id")) - rtn.uid = a.get("oid") - rtn.author_id = a.get("creator_id") - guests = a.get("event_members") - rtn.going = [uid for uid in guests if guests[uid] == "GOING"] - rtn.declined = [uid for uid in guests if guests[uid] == "DECLINED"] - rtn.invited = [uid for uid in guests if guests[uid] == "INVITED"] - return rtn - elif a.get("id") is None: - rtn = Plan( - time=a.get("event_time"), - title=a.get("event_title"), - location=a.get("event_location_name"), - location_id=a.get("event_location_id"), - ) - rtn.uid = a.get("event_id") - rtn.author_id = a.get("event_creator_id") - guests = json.loads(a.get("guest_state_list")) - else: - rtn = Plan( - time=a.get("time"), - title=a.get("event_title"), - location=a.get("location_name"), - ) - rtn.uid = a.get("id") - rtn.author_id = a.get("lightweight_event_creator").get("id") - guests = a.get("event_reminder_members").get("edges") - rtn.going = [ - m.get("node").get("id") for m in guests if m.get("guest_list_state") == "GOING" - ] - rtn.declined = [ - m.get("node").get("id") - for m in guests - if m.get("guest_list_state") == "DECLINED" - ] - rtn.invited = [ - m.get("node").get("id") - for m in guests - if m.get("guest_list_state") == "INVITED" - ] - return rtn - - def graphql_to_quick_reply(q, is_response=False): data = dict() _type = q.get("content_type").lower() @@ -235,12 +184,9 @@ def graphql_to_user(user): user["profile_picture"] = {} c_info = get_customization_info(user) plan = None - if user.get("event_reminders"): - plan = ( - graphql_to_plan(user["event_reminders"]["nodes"][0]) - if user["event_reminders"].get("nodes") - else None - ) + if user.get("event_reminders") and user["event_reminders"].get("nodes"): + plan = Plan._from_graphql(user["event_reminders"]["nodes"][0]) + return User( user["id"], url=user.get("url"), @@ -286,12 +232,8 @@ def graphql_to_thread(thread): last_name = user.get("name").split(first_name, 1).pop().strip() plan = None - if thread.get("event_reminders"): - plan = ( - graphql_to_plan(thread["event_reminders"]["nodes"][0]) - if thread["event_reminders"].get("nodes") - else None - ) + if thread.get("event_reminders") and thread["event_reminders"].get("nodes"): + plan = Plan._from_graphql(thread["event_reminders"]["nodes"][0]) return User( user["id"], @@ -327,12 +269,9 @@ def graphql_to_group(group): if "last_message" in group: last_message_timestamp = group["last_message"]["nodes"][0]["timestamp_precise"] plan = None - if group.get("event_reminders"): - plan = ( - graphql_to_plan(group["event_reminders"]["nodes"][0]) - if group["event_reminders"].get("nodes") - else None - ) + if group.get("event_reminders") and group["event_reminders"].get("nodes"): + plan = Plan._from_graphql(group["event_reminders"]["nodes"][0]) + return Group( group["thread_key"]["thread_fbid"], participants=set( @@ -368,12 +307,9 @@ def graphql_to_page(page): if page.get("city") is None: page["city"] = {} plan = None - if page.get("event_reminders"): - plan = ( - graphql_to_plan(page["event_reminders"]["nodes"][0]) - if page["event_reminders"].get("nodes") - else None - ) + if page.get("event_reminders") and page["event_reminders"].get("nodes"): + plan = Plan._from_graphql(page["event_reminders"]["nodes"][0]) + return Page( page["id"], url=page.get("url"), diff --git a/fbchat/_plan.py b/fbchat/_plan.py index b6f7826..2e228e6 100644 --- a/fbchat/_plan.py +++ b/fbchat/_plan.py @@ -2,6 +2,14 @@ from __future__ import unicode_literals import attr +import json +from ._core import Enum + + +class GuestStatus(Enum): + INVITED = 1 + GOING = 2 + DECLINED = 3 @attr.s(cmp=False) @@ -20,9 +28,76 @@ class Plan(object): location_id = attr.ib(None, converter=lambda x: x or "") #: ID of the plan creator author_id = attr.ib(None, init=False) - #: List of the people IDs who will take part in the plan - going = attr.ib(factory=list, init=False) - #: List of the people IDs who won't take part in the plan - declined = attr.ib(factory=list, init=False) - #: List of the people IDs who are invited to the plan - invited = attr.ib(factory=list, init=False) + #: Dict of `User` IDs mapped to their `GuestStatus` + guests = attr.ib(None, init=False) + + @property + def going(self): + """List of the `User` IDs who will take part in the plan.""" + return [ + id_ + for id_, status in (self.guests or {}).items() + if status is GuestStatus.GOING + ] + + @property + def declined(self): + """List of the `User` IDs who won't take part in the plan.""" + return [ + id_ + for id_, status in (self.guests or {}).items() + if status is GuestStatus.DECLINED + ] + + @property + def invited(self): + """List of the `User` IDs who are invited to the plan.""" + return [ + id_ + for id_, status in (self.guests or {}).items() + if status is GuestStatus.INVITED + ] + + @classmethod + def _from_pull(cls, data): + rtn = cls( + time=data.get("event_time"), + title=data.get("event_title"), + location=data.get("event_location_name"), + location_id=data.get("event_location_id"), + ) + rtn.uid = data.get("event_id") + rtn.author_id = data.get("event_creator_id") + rtn.guests = { + x["node"]["id"]: GuestStatus[x["guest_list_state"]] + for x in json.loads(data["guest_state_list"]) + } + return rtn + + @classmethod + def _from_fetch(cls, data): + rtn = cls( + time=data.get("event_time"), + title=data.get("title"), + location=data.get("location_name"), + location_id=str(data["location_id"]) if data.get("location_id") else None, + ) + rtn.uid = data.get("oid") + rtn.author_id = data.get("creator_id") + rtn.guests = {id_: GuestStatus[s] for id_, s in data["event_members"].items()} + return rtn + + @classmethod + def _from_graphql(cls, data): + rtn = cls( + time=data.get("time"), + title=data.get("event_title"), + location=data.get("location_name"), + ) + rtn.uid = data.get("id") + rtn.author_id = data["lightweight_event_creator"].get("id") + rtn.guests = { + x["node"]["id"]: GuestStatus[x["guest_list_state"]] + for x in data["event_reminder_members"]["edges"] + } + return rtn diff --git a/fbchat/graphql.py b/fbchat/graphql.py index 173a215..c094d6c 100644 --- a/fbchat/graphql.py +++ b/fbchat/graphql.py @@ -12,7 +12,6 @@ from ._graphql import ( graphql_to_attachment, graphql_to_extensible_attachment, graphql_to_subattachment, - graphql_to_plan, graphql_to_quick_reply, graphql_to_message, graphql_to_user, diff --git a/fbchat/models.py b/fbchat/models.py index 5c192c0..1bab61b 100644 --- a/fbchat/models.py +++ b/fbchat/models.py @@ -26,4 +26,4 @@ from ._quick_reply import ( QuickReplyEmail, ) from ._poll import Poll, PollOption -from ._plan import Plan +from ._plan import GuestStatus, Plan