HTML page to show tagged objects

This commit is contained in:
Thomas Sileo 2022-07-03 19:17:19 +02:00
parent 4a4c78bf64
commit 1acefc679d
2 changed files with 86 additions and 21 deletions

View file

@ -64,22 +64,13 @@ _RESIZED_CACHE: MutableMapping[tuple[str, int], tuple[bytes, str, Any]] = LFUCac
# TODO(ts): # TODO(ts):
# #
# Next: # Next:
# - inbox/outbox admin
# - no counters anymore?
# - allow to show tags in the menu
# - support update post with history # - support update post with history
# - inbox/outbox in the admin (as in show every objects)
# - show likes/announces counter for outbox activities
# - update actor support # - update actor support
# - hash config/profile to detect when to send Update actor # - hash config/profile to detect when to send Update actor
# #
# - [ ] block support # - [ ] block support
# - [ ] make the media proxy authenticated
# - [ ] prevent SSRF (urlutils from little-boxes) # - [ ] prevent SSRF (urlutils from little-boxes)
# - [ ] Dockerization # - [ ] Dockerization
# - [ ] Webmentions
# - [ ] custom emoji
# - [ ] poll/questions support
# - [ ] cleanup tasks # - [ ] cleanup tasks
app = FastAPI(docs_url=None, redoc_url=None) app = FastAPI(docs_url=None, redoc_url=None)
@ -564,23 +555,54 @@ async def tag_by_name(
if not tagged_count: if not tagged_count:
raise HTTPException(status_code=404) raise HTTPException(status_code=404)
outbox_objects = await db_session.execute( if is_activitypub_requested(request):
select(models.OutboxObject.ap_id) outbox_object_ids = await db_session.execute(
.join(models.TaggedOutboxObject) select(models.OutboxObject.ap_id)
.join(
models.TaggedOutboxObject,
models.TaggedOutboxObject.outbox_object_id == models.OutboxObject.id,
)
.where(*where)
.order_by(models.OutboxObject.ap_published_at.desc())
.limit(20)
)
return ActivityPubResponse(
{
"@context": ap.AS_CTX,
"id": BASE_URL + f"/t/{tag}",
"type": "OrderedCollection",
"totalItems": tagged_count,
"orderedItems": [
outbox_object.ap_id for outbox_object in outbox_object_ids
],
}
)
outbox_objects_result = await db_session.scalars(
select(models.OutboxObject)
.where(*where) .where(*where)
.join(
models.TaggedOutboxObject,
models.TaggedOutboxObject.outbox_object_id == models.OutboxObject.id,
)
.options(
joinedload(models.OutboxObject.outbox_object_attachments).options(
joinedload(models.OutboxObjectAttachment.upload)
)
)
.order_by(models.OutboxObject.ap_published_at.desc()) .order_by(models.OutboxObject.ap_published_at.desc())
.limit(20) .limit(20)
) )
# TODO(ts): implement HTML version outbox_objects = outbox_objects_result.unique().all()
# if is_activitypub_requested(request):
return ActivityPubResponse( return await templates.render_template(
db_session,
request,
"index.html",
{ {
"@context": ap.AS_CTX, "request": request,
"id": BASE_URL + f"/t/{tag}", "objects": outbox_objects,
"type": "OrderedCollection", },
"totalItems": tagged_count,
"orderedItems": [outbox_object.ap_id for outbox_object in outbox_objects],
}
) )

View file

@ -2,6 +2,9 @@ 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 import models
from app.config import generate_csrf_token
from tests.utils import generate_admin_session_cookies
def test_tags__no_tags( def test_tags__no_tags(
@ -11,3 +14,43 @@ def test_tags__no_tags(
response = client.get("/t/nope", headers={"Accept": ap.AP_CONTENT_TYPE}) response = client.get("/t/nope", headers={"Accept": ap.AP_CONTENT_TYPE})
assert response.status_code == 404 assert response.status_code == 404
def test_tags__note_with_tag(db: Session, client: TestClient) -> None:
# Call admin endpoint to create a note with
note_content = "Hello #testing"
response = client.post(
"/admin/actions/new",
data={
"redirect_url": "http://testserver/",
"content": note_content,
"visibility": ap.VisibilityEnum.PUBLIC.name,
"csrf_token": generate_csrf_token(),
},
cookies=generate_admin_session_cookies(),
)
# Then the server returns a 302
assert response.status_code == 302
# And the Follow activity was created in the outbox
outbox_object = db.query(models.OutboxObject).one()
assert outbox_object.ap_type == "Note"
assert len(outbox_object.tags) == 1
emoji_tag = outbox_object.tags[0]
assert emoji_tag["type"] == "Hashtag"
assert emoji_tag["name"] == "#testing"
# And the tag page returns this note
html_resp = client.get("/t/testing")
html_resp.raise_for_status()
assert html_resp.status_code == 200
assert "Hello" in html_resp.text
# And the AP version of the page turns the note too
ap_resp = client.get("/t/testing", headers={"Accept": ap.AP_CONTENT_TYPE})
ap_resp.raise_for_status()
ap_json_resp = ap_resp.json()
assert ap_json_resp["totalItems"] == 1
assert ap_json_resp["orderedItems"] == [outbox_object.ap_id]