2023-04-06 11:36:10 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import pytest
|
|
|
|
import fastapi
|
|
|
|
import respx
|
2023-04-07 05:47:13 +02:00
|
|
|
import httpx
|
|
|
|
from uuid import uuid4
|
2023-04-11 10:07:35 +02:00
|
|
|
from tests import factories
|
2023-05-08 06:02:56 +02:00
|
|
|
from tests.utils import build_remote_actor
|
2023-04-07 05:47:13 +02:00
|
|
|
|
|
|
|
from unittest import mock
|
2023-04-06 11:36:10 +02:00
|
|
|
from app.main import app
|
|
|
|
from app.utils import precheck
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app import activitypub as ap, httpsig
|
|
|
|
from app.config import AP_CONTENT_TYPE
|
2023-04-07 05:47:13 +02:00
|
|
|
from app import models
|
|
|
|
from sqlalchemy import select
|
2023-04-06 11:36:10 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2023-04-07 05:47:13 +02:00
|
|
|
def test_inbox_follow_request(
|
2023-04-06 11:36:10 +02:00
|
|
|
db: Session,
|
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
|
2023-04-07 08:07:59 +02:00
|
|
|
# build test actor
|
2023-05-08 06:02:56 +02:00
|
|
|
ra = build_remote_actor()
|
2023-04-07 05:47:13 +02:00
|
|
|
ap_id = ra.ap_id # type: ignore
|
2023-04-07 08:07:59 +02:00
|
|
|
|
|
|
|
# mock request
|
2023-04-07 05:47:13 +02:00
|
|
|
respx_mock.get(ap_id).mock(return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(ap_id + "/inbox").mock(return_value=httpx.Response(202))
|
|
|
|
|
2023-04-07 08:07:59 +02:00
|
|
|
# send follower request
|
2023-04-07 05:47:13 +02:00
|
|
|
with mock.patch("app.boxes.MANUALLY_APPROVES_FOLLOWERS", False):
|
2023-04-27 05:18:03 +02:00
|
|
|
follow_id = ap_id + "/follow/" + (uuid4().hex)
|
2023-04-07 05:47:13 +02:00
|
|
|
response = client.post(
|
|
|
|
"/inbox",
|
|
|
|
headers={"Content-Type": AP_CONTENT_TYPE},
|
|
|
|
json={
|
|
|
|
"@context": ap.AS_CTX,
|
|
|
|
"type": "Follow",
|
2023-04-27 05:18:03 +02:00
|
|
|
"id": follow_id,
|
2023-04-07 05:47:13 +02:00
|
|
|
"actor": ap_id,
|
|
|
|
"object": ap.ME["id"],
|
|
|
|
},
|
|
|
|
)
|
|
|
|
assert response.status_code == 202
|
|
|
|
|
2023-04-07 08:07:59 +02:00
|
|
|
# actor was saved in actor table
|
2023-04-07 05:47:13 +02:00
|
|
|
saved_actor = db.execute(select(models.Actor)).scalar_one()
|
|
|
|
assert saved_actor.ap_id == ap_id
|
|
|
|
|
2023-04-07 08:07:59 +02:00
|
|
|
# follower request was saved in outbox table
|
2023-04-07 05:47:13 +02:00
|
|
|
outbox_object = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
assert outbox_object.ap_type == "Accept"
|
2023-04-07 08:07:59 +02:00
|
|
|
|
|
|
|
# follower was saved in follower table
|
|
|
|
follower_actor = db.execute(select(models.Follower)).scalar_one()
|
|
|
|
assert follower_actor.ap_actor_id == ap_id
|
2023-04-11 12:21:00 +02:00
|
|
|
|
2023-04-27 05:18:03 +02:00
|
|
|
# send undo follower request
|
|
|
|
with mock.patch("app.boxes.MANUALLY_APPROVES_FOLLOWERS", False):
|
|
|
|
undo_id = ap_id + "/undo/" + (uuid4().hex)
|
|
|
|
response = client.post(
|
|
|
|
"/inbox",
|
|
|
|
headers={"Content-Type": AP_CONTENT_TYPE},
|
|
|
|
json={
|
|
|
|
"@context": ap.AS_CTX,
|
|
|
|
"type": "Undo",
|
|
|
|
"id": undo_id,
|
|
|
|
"actor": ap_id,
|
|
|
|
"object": {
|
|
|
|
"type": "Follow",
|
|
|
|
"id": follow_id,
|
|
|
|
"actor": ap_id,
|
|
|
|
"object": ap.ME["id"],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
assert response.status_code == 202
|
|
|
|
|
|
|
|
# follower was not saved in follower table
|
|
|
|
follower_actor = db.execute(select(models.Follower)).scalar_one_or_none()
|
|
|
|
assert follower_actor == None
|
|
|
|
|
2023-04-11 12:21:00 +02:00
|
|
|
|
|
|
|
def test_inbox_announce_request(
|
|
|
|
db: Session,
|
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
|
|
|
|
# build test actor
|
2023-05-08 06:02:56 +02:00
|
|
|
ra = build_remote_actor()
|
2023-04-11 12:21:00 +02:00
|
|
|
|
|
|
|
ap_id = ra.ap_id # type: ignore
|
|
|
|
app.dependency_overrides[precheck.inbox_prechecker] = factories.inbox_prechecker
|
|
|
|
|
|
|
|
# mock request
|
|
|
|
respx_mock.get(ap_id).mock(return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(ap_id + "/inbox").mock(return_value=httpx.Response(202))
|
|
|
|
|
|
|
|
from app.models import now
|
|
|
|
from app.activitypub import VisibilityEnum
|
|
|
|
|
|
|
|
note_id = ap.ME["id"] + (uuid4().hex)
|
|
|
|
published = now().replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
|
|
|
note_object = {
|
|
|
|
"@context": ap.AS_EXTENDED_CTX,
|
|
|
|
"type": "Note",
|
|
|
|
"id": note_id,
|
|
|
|
"attributedTo": ap.ME["id"],
|
|
|
|
"content": "<p>Test!</p>",
|
|
|
|
"to": [ap.AS_PUBLIC],
|
|
|
|
"cc": [],
|
|
|
|
"published": published,
|
|
|
|
# "context": context,
|
|
|
|
# "conversation": context,
|
|
|
|
"url": note_id,
|
|
|
|
"tag": [],
|
|
|
|
"summary": None,
|
|
|
|
"inReplyTo": None,
|
|
|
|
"sensitive": False,
|
|
|
|
"attachment": [],
|
|
|
|
}
|
|
|
|
|
|
|
|
outbox_object = models.OutboxObject(
|
|
|
|
public_id=note_id,
|
|
|
|
ap_object=note_object,
|
|
|
|
ap_id=note_id,
|
|
|
|
ap_type="Note",
|
|
|
|
visibility =VisibilityEnum.PUBLIC,
|
|
|
|
)
|
|
|
|
|
|
|
|
db.add(outbox_object)
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
# send announce request
|
|
|
|
response = client.post(
|
|
|
|
"/inbox",
|
|
|
|
headers={"Content-Type": AP_CONTENT_TYPE},
|
|
|
|
json={
|
|
|
|
"@context": ap.AS_CTX,
|
|
|
|
"type": "Announce",
|
|
|
|
"id": ap_id + "/announce/" + (uuid4().hex),
|
|
|
|
"actor": ap_id,
|
|
|
|
"object": note_id,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
assert response.status_code == 202
|
|
|
|
|
|
|
|
saved_note = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
print(saved_note.ap_id)
|
2023-04-11 17:03:53 +02:00
|
|
|
assert saved_note.announces_count == 1 # TODO WIP
|