예제 #1
0
def post_to_inbox(activity: ap.BaseActivity) -> None:
    # Check for Block activity
    actor = activity.get_actor()
    if outbox_is_blocked(actor.id):
        logger.info(
            f"actor {actor!r} is blocked, dropping the received activity {activity!r}"
        )
        return

    # If the message is coming from a Pleroma relay, we process it as a possible reply for a stream activity
    if (actor.has_type(ap.ActivityType.APPLICATION)
            and actor.id.endswith("/relay")
            and activity.has_type(ap.ActivityType.ANNOUNCE)
            and not find_one_activity({
                **by_object_id(activity.get_object_id()),
                **by_type(ap.ActivityType.CREATE),
            }) and
            not DB.replies.find_one(by_remote_id(activity.get_object_id()))):
        Tasks.process_reply(activity.get_object_id())
        return

    # Hubzilla sends Update with the same ID as the actor, and it poisons the cache
    if (activity.has_type(ap.ActivityType.UPDATE)
            and activity.id == activity.get_object_id()):
        # Start a task to update the cached actor
        Tasks.cache_actor(activity.id)
        return

    # Honk forwards activities in a Read, process them as replies
    if activity.has_type(ap.ActivityType.READ):
        Tasks.process_reply(activity.get_object_id())
        return

    # TODO(tsileo): support ignore from Honk

    # Hubzilla forwards activities in a Create, process them as possible replies
    if activity.has_type(ap.ActivityType.CREATE) and server(
            activity.id) != server(activity.get_object_id()):
        Tasks.process_reply(activity.get_object_id())
        return

    if DB.activities.find_one({
            "box": Box.INBOX.value,
            "remote_id": activity.id
    }):
        # The activity is already in the inbox
        logger.info(f"received duplicate activity {activity!r}, dropping it")
        return

    save(Box.INBOX, activity)
    logger.info(f"spawning tasks for {activity!r}")
    if not activity.has_type([ap.ActivityType.DELETE, ap.ActivityType.UPDATE]):
        Tasks.cache_actor(activity.id)
    Tasks.process_new_activity(activity.id)
    Tasks.finish_post_to_inbox(activity.id)
예제 #2
0
파일: backend.py 프로젝트: smonff/reel2bits
    def new_following(self, activity: ap.BaseActivity, obj: ap.BaseActivity) -> None:
        current_app.logger.info("new following")

        ap_from = obj.get_actor()  # Who initiated the follow
        ap_to = activity.get_actor()  # who to be followed

        db_from = Actor.query.filter(Actor.url == ap_from.id).first()
        db_to = Actor.query.filter(Actor.url == ap_to.id).first()
        if not db_from:
            current_app.logger.error(f"cannot find actor {ap_from!r}")
            return
        if not db_to:
            current_app.logger.error(f"cannot find follow {ap_to!r}")
            return

        current_app.logger.info(f"{db_from.name} wanted to follow {db_to.name}")

        # FIXME: may be the reverse, db_follow follow db_actor
        db_from.follow(activity.id, db_to)
        db.session.commit()
        current_app.logger.info("new following saved")
예제 #3
0
 def outbox_new(self, as_actor: ap.Person,
                activity: ap.BaseActivity) -> None:
     print(f"saving {activity!r} to DB")
     actor_id = activity.get_actor().id
     if activity.id in self.OUTBOX_IDX[actor_id]:
         return
     self.DB[actor_id]["outbox"].append(activity)
     self.OUTBOX_IDX[actor_id][activity.id] = activity
     self.FETCH_MOCK[activity.id] = activity.to_dict()
     if isinstance(activity, ap.Create):
         self.FETCH_MOCK[
             activity.get_object().id] = activity.get_object().to_dict()
예제 #4
0
    def save(self, box: Box, activity: ap.BaseActivity) -> None:
        """Save an Activity in database"""

        current_app.logger.info(f"asked to save an activity {activity!r}")

        # Save remote Actor
        ap_actor = activity.get_actor()
        domain = urlparse(ap_actor.id)
        current_app.logger.debug(f"actor.id=={ap_actor.__dict__}")

        current_app.logger.debug(f"actor domain {domain.netloc} and " f"name {ap_actor.preferredUsername}")

        actor = Actor.query.filter(Actor.domain == domain.netloc, Actor.name == ap_actor.preferredUsername).first()

        # FIXME TODO: check if it still works with unknown remote actor
        if not actor:
            current_app.logger.debug("cannot find actor")
            actor = Actor.query.filter(Actor.url == ap_actor.id).first()
            if not actor:
                current_app.logger.debug(f"actor {ap_actor.id} not found")
                actor, user = create_remote_actor(ap_actor)
                db.session.add(user)
                db.session.add(actor)
                current_app.logger.debug("created one in DB")
            else:
                current_app.logger.debug(f"got local one {actor.url}")
        else:
            current_app.logger.debug(f"got remote one {actor.url}")

        # Save Activity
        act = Activity()
        act.payload = activity.to_dict()
        act.url = activity.id
        act.type = activity.type
        act.box = box.value

        # Activity is local only if the url starts like BASE_URL
        base_url = current_app.config["BASE_URL"]
        act.local = activity.id.startswith(base_url)

        act.actor_id = actor.id

        db.session.add(act)

        db.session.commit()
예제 #5
0
def post_to_inbox(activity: ap.BaseActivity) -> None:
    # Check for Block activity
    actor = activity.get_actor()
    if back.outbox_is_blocked(MY_PERSON, actor.id):
        log.info(
            f"actor {actor!r} is blocked, dropping the received activity {activity!r}"
        )
        return

    if back.inbox_check_duplicate(MY_PERSON, activity.id):
        # The activity is already in the inbox
        log.info(f"received duplicate activity {activity!r}, dropping it")

    back.save(Box.INBOX, activity)
    process_new_activity.delay(activity.id)

    log.info(f"spawning task for {activity!r}")
    finish_post_to_inbox.delay(activity.id)
예제 #6
0
def accept_follow(activity: ap.BaseActivity) -> str:
    actor_id = activity.get_actor().id
    accept = ap.Accept(
        actor=ID,
        context=new_context(activity),
        object={
            "type": "Follow",
            "id": activity.id,
            "object": activity.get_object_id(),
            "actor": actor_id,
        },
        to=[actor_id],
        published=now(),
    )
    update_one_activity(
        by_remote_id(activity.id),
        upsert({MetaKey.FOLLOW_STATUS: FollowStatus.ACCEPTED.value}),
    )
    return post_to_outbox(accept)
예제 #7
0
def _meta(activity: ap.BaseActivity) -> _NewMeta:
    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

    return {
        MetaKey.UNDO.value:
        False,
        MetaKey.DELETED.value:
        False,
        MetaKey.PUBLIC.value:
        is_public,
        MetaKey.SERVER.value:
        urlparse(activity.id).netloc,
        MetaKey.VISIBILITY.value:
        visibility.name,
        MetaKey.ACTOR_ID.value:
        actor_id,
        MetaKey.OBJECT_ID.value:
        object_id,
        MetaKey.OBJECT_VISIBILITY.value:
        object_visibility,
        MetaKey.POLL_ANSWER.value:
        False,
        MetaKey.PUBLISHED.value:
        activity.published if activity.published else now(),
    }
예제 #8
0
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,
        },
    })
예제 #9
0
def post_to_inbox(activity: ap.BaseActivity) -> None:
    # Check for Block activity
    actor = activity.get_actor()
    if outbox_is_blocked(actor.id):
        logger.info(
            f"actor {actor!r} is blocked, dropping the received activity {activity!r}"
        )
        return

    if DB.activities.find_one({
            "box": Box.INBOX.value,
            "remote_id": activity.id
    }):
        # The activity is already in the inbox
        logger.info(f"received duplicate activity {activity!r}, dropping it")
        return

    save(Box.INBOX, activity)
    Tasks.process_new_activity(activity.id)

    logger.info(f"spawning task for {activity!r}")
    Tasks.finish_post_to_inbox(activity.id)
예제 #10
0
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,
        },
    })