[feat] add FOLLOWERS_ONLY visibility support
All checks were successful
/ run-pytest (push) Successful in 2m10s
All checks were successful
/ run-pytest (push) Successful in 2m10s
This commit is contained in:
parent
253970094b
commit
4a330c3678
4 changed files with 48 additions and 10 deletions
|
@ -438,6 +438,9 @@ async def _send_create(
|
||||||
elif visibility == ap.VisibilityEnum.UNLISTED:
|
elif visibility == ap.VisibilityEnum.UNLISTED:
|
||||||
to = [f"{BASE_URL}/followers"]
|
to = [f"{BASE_URL}/followers"]
|
||||||
cc = [ap.AS_PUBLIC]
|
cc = [ap.AS_PUBLIC]
|
||||||
|
elif visibility == ap.VisibilityEnum.FOLLOWERS_ONLY:
|
||||||
|
to = [f"{BASE_URL}/followers"]
|
||||||
|
cc = []
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unsupport visibility {visibility}")
|
raise ValueError(f"Unsupport visibility {visibility}")
|
||||||
|
|
||||||
|
|
10
app/hysql.hy
10
app/hysql.hy
|
@ -2,6 +2,7 @@
|
||||||
(import app [models])
|
(import app [models])
|
||||||
(import app.database [async_session])
|
(import app.database [async_session])
|
||||||
(import sqlalchemy [select])
|
(import sqlalchemy [select])
|
||||||
|
(import app.activitypub [VisibilityEnum])
|
||||||
(import pprint [pprint])
|
(import pprint [pprint])
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,3 +11,12 @@
|
||||||
(.all (await (.scalars db
|
(.all (await (.scalars db
|
||||||
(.where (select models.InboxObject)
|
(.where (select models.InboxObject)
|
||||||
(= models.InboxObject.ap_type ap_type))))))
|
(= models.InboxObject.ap_type ap_type))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn/a get_index_status
|
||||||
|
[db]
|
||||||
|
(.all (await
|
||||||
|
(.scalars db
|
||||||
|
(.where (select models.OutboxObject)
|
||||||
|
(.in_ models.OutboxObject.visibility [VisibilityEnum.PUBLIC VisibilityEnum.UNLISTED])
|
||||||
|
(.is_ models.OutboxObject.is_deleted False))))))
|
||||||
|
|
12
app/main.py
12
app/main.py
|
@ -30,6 +30,7 @@ from app.boxes import save_incoming
|
||||||
from app.activitypub import VisibilityEnum
|
from app.activitypub import VisibilityEnum
|
||||||
from app.boxes import _send_create
|
from app.boxes import _send_create
|
||||||
from app.orgpython import to_html
|
from app.orgpython import to_html
|
||||||
|
from app.hysql import get_index_status
|
||||||
|
|
||||||
|
|
||||||
def _check_0rtt_early_data(request: Request) -> None:
|
def _check_0rtt_early_data(request: Request) -> None:
|
||||||
|
@ -81,16 +82,7 @@ async def index(
|
||||||
if is_ap_requested(request):
|
if is_ap_requested(request):
|
||||||
return ActivityPubResponse(ME)
|
return ActivityPubResponse(ME)
|
||||||
|
|
||||||
statues = (
|
statues = await get_index_status(db_session)
|
||||||
await db_session.scalars(
|
|
||||||
select(models.OutboxObject)
|
|
||||||
.where(
|
|
||||||
models.OutboxObject.ap_type == "Note",
|
|
||||||
models.OutboxObject.is_deleted.is_(False),
|
|
||||||
)
|
|
||||||
.order_by(models.OutboxObject.created_at.desc())
|
|
||||||
)
|
|
||||||
).all()
|
|
||||||
|
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request,
|
request,
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import pytest
|
import pytest
|
||||||
|
import httpx
|
||||||
|
import respx
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from app import activitypub as ap
|
from app import activitypub as ap
|
||||||
from app.config import AP_CONTENT_TYPE
|
from app.config import AP_CONTENT_TYPE
|
||||||
|
from tests.utils import build_remote_actor
|
||||||
|
|
||||||
|
|
||||||
_ACCEPTED_AP_HEADERS = [
|
_ACCEPTED_AP_HEADERS = [
|
||||||
|
@ -26,3 +29,33 @@ def test_index__ap(db: Session, client: TestClient, accept: str):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.headers["content-type"] == AP_CONTENT_TYPE
|
assert response.headers["content-type"] == AP_CONTENT_TYPE
|
||||||
assert response.json() == ap.ME
|
assert response.json() == ap.ME
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_follow_only_status(
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
response = client.post(
|
||||||
|
"/outbox",
|
||||||
|
headers={"Authorization": "Basic test-token"},
|
||||||
|
content='{"visibility": "followers-only","content": "note content"}'
|
||||||
|
)
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
# And the Note was not show in the index
|
||||||
|
|
||||||
|
indext_content = client.get("/").text
|
||||||
|
assert "note content" not in indext_content
|
||||||
|
|
Loading…
Reference in a new issue