2023-04-28 09:25:00 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import pytest
|
|
|
|
import fastapi
|
|
|
|
import respx
|
|
|
|
import httpx
|
|
|
|
from uuid import uuid4
|
|
|
|
from tests import factories
|
2023-05-08 06:02:56 +02:00
|
|
|
from tests.utils import build_remote_actor
|
2023-04-28 09:25:00 +02:00
|
|
|
|
|
|
|
from unittest import mock
|
|
|
|
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
|
|
|
|
from app import models
|
|
|
|
from sqlalchemy import select
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
async def test_outbox_send_follow_request(
|
|
|
|
db: Session,
|
2023-07-30 14:50:08 +02:00
|
|
|
async_db_session,
|
2023-04-28 09:25:00 +02:00
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
# build test actor
|
2023-05-08 06:02:56 +02:00
|
|
|
ra = build_remote_actor()
|
2023-04-28 09:25:00 +02:00
|
|
|
remote_ap_id = ra.ap_id # type: ignore
|
|
|
|
|
|
|
|
# mock request
|
|
|
|
respx_mock.get(remote_ap_id).mock(
|
|
|
|
return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(remote_ap_id + "/inbox").mock(
|
|
|
|
return_value=httpx.Response(202))
|
|
|
|
|
|
|
|
from app.boxes import send_follow
|
|
|
|
|
2023-07-30 14:50:08 +02:00
|
|
|
async with async_db_session as db_session: #type: ignore
|
2023-04-28 09:25:00 +02:00
|
|
|
await send_follow(db_session, remote_ap_id)
|
|
|
|
|
|
|
|
# And the Follow activity was created in the outbox
|
|
|
|
outbox_object = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
assert outbox_object.ap_type == "Follow"
|
|
|
|
assert outbox_object.activity_object_ap_id == remote_ap_id
|
2023-05-08 05:55:46 +02:00
|
|
|
|
2023-07-30 23:52:23 +02:00
|
|
|
response = client.post(
|
|
|
|
"/inbox",
|
|
|
|
headers={"Content-Type": AP_CONTENT_TYPE},
|
|
|
|
json={
|
|
|
|
"@context": ap.AS_CTX,
|
|
|
|
"type": "Accept",
|
|
|
|
"id": "https://accept-test",
|
|
|
|
"actor": remote_ap_id,
|
|
|
|
"object": outbox_object.ap_id,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert response.status_code == 202
|
|
|
|
|
|
|
|
# follower was saved in follower table
|
|
|
|
following_actor = db.execute(select(models.Following)).scalar_one()
|
|
|
|
assert following_actor.ap_actor_id == remote_ap_id
|
2023-08-03 14:59:58 +02:00
|
|
|
assert following_actor.outbox_object == outbox_object
|
|
|
|
|
|
|
|
inbox_object = db.execute(select(models.InboxObject)).scalar_one()
|
|
|
|
assert inbox_object.ap_type == "Accept"
|
|
|
|
|
|
|
|
|
2023-07-30 23:52:23 +02:00
|
|
|
@pytest.mark.asyncio
|
|
|
|
async def test_outbox_send_follow_request_nest_accept(
|
|
|
|
db: Session,
|
|
|
|
async_db_session,
|
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
# build test actor
|
|
|
|
ra = build_remote_actor()
|
|
|
|
remote_ap_id = ra.ap_id # type: ignore
|
|
|
|
|
|
|
|
# mock request
|
|
|
|
respx_mock.get(remote_ap_id).mock(
|
|
|
|
return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(remote_ap_id + "/inbox").mock(
|
|
|
|
return_value=httpx.Response(202))
|
|
|
|
|
|
|
|
from app.boxes import send_follow
|
|
|
|
|
|
|
|
async with async_db_session as db_session: #type: ignore
|
|
|
|
await send_follow(db_session, remote_ap_id)
|
|
|
|
|
|
|
|
# And the Follow activity was created in the outbox
|
|
|
|
outbox_object = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
assert outbox_object.ap_type == "Follow"
|
|
|
|
assert outbox_object.activity_object_ap_id == remote_ap_id
|
|
|
|
|
|
|
|
response = client.post(
|
|
|
|
"/inbox",
|
|
|
|
headers={"Content-Type": AP_CONTENT_TYPE},
|
|
|
|
json={
|
|
|
|
"@context": ap.AS_CTX,
|
|
|
|
"type": "Accept",
|
|
|
|
"id": "https://accept-test",
|
|
|
|
"actor": remote_ap_id,
|
|
|
|
"object": {
|
|
|
|
"id": outbox_object.ap_id,
|
|
|
|
"type": "Accept",
|
|
|
|
"actor": ap.ME["id"],
|
|
|
|
"object": remote_ap_id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert response.status_code == 202
|
|
|
|
|
|
|
|
# follower was saved in follower table
|
|
|
|
following_actor = db.execute(select(models.Following)).scalar_one()
|
|
|
|
assert following_actor.ap_actor_id == remote_ap_id
|
|
|
|
|
2023-05-08 05:55:46 +02:00
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
async def test_outbox_send_create_activity(
|
|
|
|
db: Session,
|
2023-07-30 14:50:08 +02:00
|
|
|
async_db_session,
|
2023-05-08 05:55:46 +02:00
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
# build test actor
|
2023-05-08 06:02:56 +02:00
|
|
|
ra = build_remote_actor()
|
2023-05-08 05:55:46 +02:00
|
|
|
remote_ap_id = ra.ap_id # type: ignore
|
|
|
|
|
|
|
|
# mock request
|
|
|
|
respx_mock.get(remote_ap_id).mock(
|
|
|
|
return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(remote_ap_id + "/inbox").mock(
|
|
|
|
return_value=httpx.Response(202))
|
|
|
|
|
|
|
|
from app.boxes import _send_create
|
|
|
|
from app.activitypub import VisibilityEnum
|
|
|
|
from app.orgpython import to_html
|
|
|
|
|
2023-07-30 14:50:08 +02:00
|
|
|
async with async_db_session as db_session: #type: ignore
|
2023-05-08 05:55:46 +02:00
|
|
|
content = "*Blod Text* =code Text= \n"
|
|
|
|
content = to_html(content)
|
|
|
|
|
|
|
|
await _send_create(
|
|
|
|
db_session,
|
|
|
|
"Note",
|
|
|
|
content,
|
|
|
|
VisibilityEnum.PUBLIC
|
|
|
|
)
|
|
|
|
|
|
|
|
# And the Follow activity was created in the outbox
|
|
|
|
outbox_object = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
assert outbox_object.ap_type == "Note"
|
|
|
|
assert outbox_object.ap_object["content"] == content
|
2024-03-04 13:57:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
async def test_outbox_send_unlisted_note(
|
|
|
|
db: Session,
|
|
|
|
async_db_session,
|
|
|
|
client: TestClient,
|
|
|
|
respx_mock: respx.MockRouter,
|
|
|
|
) -> None:
|
|
|
|
# build test actor
|
|
|
|
ra = build_remote_actor()
|
|
|
|
remote_ap_id = ra.ap_id # type: ignore
|
|
|
|
|
|
|
|
# mock request
|
|
|
|
respx_mock.get(remote_ap_id).mock(
|
|
|
|
return_value=httpx.Response(200,json=ra.ap_actor))
|
|
|
|
respx_mock.post(remote_ap_id + "/inbox").mock(
|
|
|
|
return_value=httpx.Response(202))
|
|
|
|
|
|
|
|
from app.activitypub import VisibilityEnum
|
|
|
|
|
|
|
|
|
|
|
|
response = client.post(
|
|
|
|
"/outbox",
|
|
|
|
headers={"Authorization": "Basic test-token"},
|
|
|
|
content='{"visibility": "unlisted","content": "note content"}'
|
|
|
|
)
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
# And the Follow activity was created in the outbox
|
|
|
|
outbox_object = db.execute(select(models.OutboxObject)).scalar_one()
|
|
|
|
assert outbox_object.ap_type == "Note"
|
|
|
|
assert outbox_object.visibility == VisibilityEnum.UNLISTED
|