Exemplo n.º 1
0
def follow(username_or_id):
    """
    Follow an account.
    ---
    tags:
        - Accounts
    parameters:
        - name: id
          in: query
          type: integer
          required: true
          description: User ID to follow
    responses:
      200:
        description: Returns Relationship
        schema:
            $ref: '#/definitions/Relationship'
    """
    current_user = current_token.user
    if not current_user:
        abort(400)

    user = User.query.filter(User.name == username_or_id,
                             User.local.is_(True)).first()
    if not user:
        try:
            user = User.query.filter(User.flake_id == username_or_id).first()
        except sqlalchemy.exc.DataError:
            abort(404)
    if not user:
        abort(404)

    actor_me = current_user.actor[0]
    actor_them = user.actor[0]

    if user.local:
        actor_me.follow(None, actor_them)
        return jsonify([to_json_relationship(current_user, user)])
    else:
        # We need to initiate a follow request
        # Check if not already following
        rel = Follower.query.filter(
            Follower.actor_id == actor_me.id,
            Follower.target_id == actor_them.id).first()

        if not rel:
            # Initiate a Follow request from actor_me to actor_target
            follow = ap.Follow(actor=actor_me.url, object=actor_them.url)
            post_to_outbox(follow)
            return jsonify(""), 202
        else:
            return jsonify({"error": "already following"}), 409
Exemplo n.º 2
0
def unfollow():
    user = request.args.get("user")

    actor_me = current_user.actor[0]

    if user.startswith("https://"):
        actor = Actor.query.filter(Actor.url == user).first()
        local_user = actor.user
    else:
        local_user = User.query.filter(User.name == user).first()

    if local_user:
        # Process local unfollow
        actor_me.unfollow(local_user.actor[0])
        flash(gettext("Unfollow successful"), "success")
    else:
        # Might be a remote unfollow

        # 1. Webfinger the user
        try:
            remote_actor_url = get_actor_url(user, debug=current_app.debug)
        except InvalidURLError:
            current_app.logger.exception(f"Invalid webfinger URL: {user}")
            remote_actor_url = None
        except requests.exceptions.HTTPError:
            current_app.logger.exception(f"Invali webfinger URL: {user}")
            remote_actor_url = None

        if not remote_actor_url:
            flash(gettext("User not found"), "error")
            return redirect(url_for("bp_users.profile",
                                    name=current_user.name))

        # 2. Check if we have a local user
        actor_target = Actor.query.filter(
            Actor.url == remote_actor_url).first()

        if not actor_target:
            # 2.5 Fetch and save remote actor
            backend = ap.get_backend()
            iri = backend.fetch_iri(remote_actor_url)
            if not iri:
                flash(gettext("User not found"), "error")
                return redirect(url_for("bp_main.home"))
            act = ap.parse_activity(iri)
            actor_target, user_target = create_remote_actor(act)
            db.session.add(user_target)
            db.session.add(actor_target)

        # 2.5 Get the relation of the follow
        follow_relation = Follower.query.filter(
            Follower.actor_id == actor_me.id,
            Follower.target_id == actor_target.id).first()
        if not follow_relation:
            flash(gettext("You don't follow this user"), "error")
            return redirect(url_for("bp_users.profile",
                                    name=current_user.name))

        # 3. Fetch the Activity of the Follow
        accept_activity = Activity.query.filter(
            Activity.url == follow_relation.activity_url).first()
        if not accept_activity:
            current_app.logger.error(
                f"cannot find accept activity {follow_relation.activity_url}")
            flash(gettext("Whoops, something went wrong"))
            return redirect(url_for("bp_users.profile",
                                    name=current_user.name))
        # Then the Activity ID of the Accept will be the object id
        activity = ap.parse_activity(payload=accept_activity.payload)

        # Get the final activity (the Follow one)
        follow_activity = Activity.query.filter(
            Activity.url == activity.get_object_id()).first()
        if not follow_activity:
            current_app.logger.error(
                f"cannot find follow activity {activity.get_object_id()}")
            flash(gettext("Whoops, something went wrong"))
            return redirect(url_for("bp_users.profile",
                                    name=current_user.name))

        ap_follow_activity = ap.parse_activity(payload=follow_activity.payload)

        # 4. Initiate a Follow request from actor_me to actor_target
        unfollow = ap_follow_activity.build_undo()
        post_to_outbox(unfollow)
        flash(gettext("Unfollow request have been transmitted"), "success")

    return redirect(url_for("bp_users.profile", name=current_user.name))
Exemplo n.º 3
0
def follow():
    user = request.args.get("user")

    actor_me = current_user.actor[0]

    if user.startswith("https://"):
        actor = Actor.query.filter(Actor.url == user).first()
        if actor:
            local_user = actor.user
        else:
            local_user = None
    else:
        local_user = User.query.filter(User.name == user).first()

    if local_user:
        # Process local follow
        actor_me.follow(None, local_user.actor[0])
        flash(gettext("Follow successful"), "success")
    else:
        # Might be a remote follow

        # 1. Webfinger the user
        try:
            remote_actor_url = get_actor_url(user, debug=current_app.debug)
        except InvalidURLError:
            current_app.logger.exception(f"Invalid webfinger URL: {user}")
            remote_actor_url = None
        # except requests.exceptions.HTTPError:
        #    current_app.logger.exception(f"Invali webfinger URL: {user}")
        #    remote_actor_url = None

        if not remote_actor_url:
            flash(gettext("User not found"), "error")
            return redirect(url_for("bp_users.profile",
                                    name=current_user.name))

        # 2. Check if we have a local user
        actor_target = Actor.query.filter(
            Actor.url == remote_actor_url).first()

        if not actor_target:
            # 2.5 Fetch and save remote actor
            backend = ap.get_backend()
            iri = backend.fetch_iri(remote_actor_url)
            if not iri:
                flash(gettext("User not found"), "error")
                return redirect(url_for("bp_main.home"))
            act = ap.parse_activity(iri)
            actor_target, user_target = create_remote_actor(act)
            db.session.add(user_target)
            db.session.add(actor_target)

        # 2.7 Check if we already have a relation
        rel = Follower.query.filter(
            Follower.actor_id == actor_me.id,
            Follower.target_id == actor_target.id).first()

        if not rel:
            # 3. Initiate a Follow request from actor_me to actor_target
            follow = ap.Follow(actor=actor_me.url, object=actor_target.url)
            post_to_outbox(follow)
            flash(gettext("Follow request have been transmitted"), "success")
        else:
            flash(gettext("You already follow this user", "info"))

    return redirect(url_for("bp_users.profile", name=current_user.name))
Exemplo n.º 4
0
def unfollow(username_or_id):
    """
    Unfollow an account.
    ---
    tags:
        - Accounts
    parameters:
        - name: id
          in: path
          type: integer
          required: true
          description: User ID to follow
    responses:
      200:
        description: Returns Relationship
        schema:
            $ref: '#/definitions/Relationship'
    """
    current_user = current_token.user
    if not current_user:
        abort(400)

    user = User.query.filter(User.name == username_or_id, User.local.is_(True)).first()
    if not user:
        try:
            user = User.query.filter(User.flake_id == username_or_id).first()
        except sqlalchemy.exc.DataError:
            abort(404)
    if not user:
        abort(404)

    actor_me = current_user.actor[0]
    actor_them = user.actor[0]

    if user.local:
        actor_me.unfollow(actor_them)
        return jsonify([to_json_relationship(current_user, user)])
    else:
        # Get the relation of the follow
        follow_relation = Follower.query.filter(
            Follower.actor_id == actor_me.id, Follower.target_id == actor_them.id
        ).first()
        if not follow_relation:
            return jsonify({"error": "follow relation not found"}), 404

        # Fetch the related Activity of the Follow relation
        accept_activity = Activity.query.filter(Activity.url == follow_relation.activity_url).first()
        if not accept_activity:
            current_app.logger.error(f"cannot find accept activity {follow_relation.activity_url}")
            return jsonify({"error": "cannot found the accept activity"}), 500
        # Then the Activity ID of the ACcept will be the object id
        activity = ap.parse_activity(payload=accept_activity.payload)

        # get the final activity (the Follow one)
        follow_activity = Activity.query.filter(Activity.url == activity.get_object_id()).first()
        if not follow_activity:
            current_app.logger.error(f"cannot find follow activity {activity.get_object_id()}")
            return jsonify({"error": "cannot find follow activity"}), 500

        ap_follow_activity = ap.parse_activity(payload=follow_activity.payload)

        # initiate an Undo of the Follow request
        unfollow = ap_follow_activity.build_undo()
        post_to_outbox(unfollow)
        return jsonify(""), 202