def _is_local_reply(activity: ap.BaseActivity) -> bool: for dest in _to_list(activity.to or []): if dest.startswith(config.BASE_URL): return True for dest in _to_list(activity.cc or []): if dest.startswith(config.BASE_URL): return True return False
def _is_local_reply(create: ap.Create) -> bool: for dest in _to_list(create.to or []): if dest.startswith(BASE_URL): return True for dest in _to_list(create.cc or []): if dest.startswith(BASE_URL): return True return False
def save(box: Box, activity: ap.BaseActivity) -> None: """Custom helper for saving an activity to the DB.""" # Set some "type"-related neta meta = _meta(activity) if box == Box.OUTBOX and activity.has_type(ap.ActivityType.FOLLOW): meta[MetaKey.FOLLOW_STATUS.value] = FollowStatus.WAITING.value elif activity.has_type(ap.ActivityType.CREATE): mentions = [] obj = activity.get_object() for m in obj.get_mentions(): mentions.append(m.href) hashtags = [] for h in obj.get_hashtags(): hashtags.append(h.name[1:]) # Strip the # meta.update( {MetaKey.MENTIONS.value: mentions, MetaKey.HASHTAGS.value: hashtags} ) DB.activities.insert_one( { "box": box.value, "activity": activity.to_dict(), "type": _to_list(activity.type), "remote_id": activity.id, "meta": meta, } )
def save(self, box: Box, activity: ap.BaseActivity) -> None: """Custom helper for saving an activity to the DB.""" DB.activities.insert_one( { "box": box.value, "activity": activity.to_dict(), "type": _to_list(activity.type), "remote_id": activity.id, "meta": {"undo": False, "deleted": False}, } )
def save(self, box: Box, activity: ap.BaseActivity) -> None: """Custom helper for saving an activity to the DB.""" is_public = True if activity.has_type( ap.ActivityType.CREATE) and not activity.is_public(): is_public = False DB.activities.insert_one({ "box": box.value, "activity": activity.to_dict(), "type": _to_list(activity.type), "remote_id": activity.id, "meta": { "undo": False, "deleted": False, "public": is_public }, })
def save(box: Box, activity: ap.BaseActivity) -> None: """Custom helper for saving an activity to the DB.""" visibility = ap.get_visibility(activity) is_public = False if visibility in [ap.Visibility.PUBLIC, ap.Visibility.UNLISTED]: is_public = True object_id = None try: object_id = activity.get_object_id() except Exception: # TODO(tsileo): should be ValueError, but replies trigger a KeyError on object pass object_visibility = None if activity.has_type([ ap.ActivityType.CREATE, ap.ActivityType.ANNOUNCE, ap.ActivityType.LIKE ]): object_visibility = ap.get_visibility(activity.get_object()).name actor_id = activity.get_actor().id DB.activities.insert_one({ "box": box.value, "activity": activity.to_dict(), "type": _to_list(activity.type), "remote_id": activity.id, "meta": { "undo": False, "deleted": False, "public": is_public, "server": urlparse(activity.id).netloc, "visibility": visibility.name, "actor_id": actor_id, "object_id": object_id, "object_visibility": object_visibility, "poll_answer": False, }, })
def save_reply(activity: ap.BaseActivity, meta: Dict[str, Any] = {}) -> None: visibility = ap.get_visibility(activity) is_public = False if visibility in [ap.Visibility.PUBLIC, ap.Visibility.UNLISTED]: is_public = True published = activity.published if activity.published else now() DB.replies.insert_one({ "activity": activity.to_dict(), "type": _to_list(activity.type), "remote_id": activity.id, "meta": { "undo": False, "deleted": False, "public": is_public, "server": urlparse(activity.id).netloc, "visibility": visibility.name, "actor_id": activity.get_actor().id, MetaKey.PUBLISHED.value: published, **meta, }, })
def _handle_replies(self, as_actor: ap.Person, create: ap.Create) -> None: """Go up to the root reply, store unknown replies in the `threads` DB and set the "meta.thread_root_parent" key to make it easy to query a whole thread.""" in_reply_to = create.get_object().get_in_reply_to() if not in_reply_to: return new_threads = [] root_reply = in_reply_to reply = ap.fetch_remote_activity(root_reply) # Ensure the this is a local reply, of a question, with a direct "to" addressing if (reply.id.startswith(BASE_URL) and reply.has_type(ap.ActivityType.QUESTION.value) and _to_list(create.get_object().to)[0].startswith(BASE_URL) and not create.is_public()): return self._process_question_reply(create, reply) elif (create.id.startswith(BASE_URL) and reply.has_type(ap.ActivityType.QUESTION.value) and not create.is_public()): # Keep track of our own votes DB.activities.update_one( { "activity.object.id": reply.id, "box": "inbox" }, {"$set": { "meta.voted_for": create.get_object().name }}, ) return None creply = DB.activities.find_one_and_update( {"activity.object.id": in_reply_to}, {"$inc": { "meta.count_reply": 1, "meta.count_direct_reply": 1 }}, ) if not creply: # It means the activity is not in the inbox, and not in the outbox, we want to save it self.save(Box.REPLIES, reply) new_threads.append(reply.id) # TODO(tsileo): parses the replies collection and import the replies? while reply is not None: in_reply_to = reply.get_in_reply_to() if not in_reply_to: break root_reply = in_reply_to reply = ap.fetch_remote_activity(root_reply) q = {"activity.object.id": root_reply} if not DB.activities.count(q): self.save(Box.REPLIES, reply) new_threads.append(reply.id) DB.activities.update_one( {"remote_id": create.id}, {"$set": { "meta.thread_root_parent": root_reply }}) DB.activities.update( { "box": Box.REPLIES.value, "remote_id": { "$in": new_threads } }, {"$set": { "meta.thread_root_parent": root_reply }}, )
def has_type(doc, _types): for _type in _to_list(_types): if _type in _to_list(doc["type"]): return True return False