HTML page to show tagged objects
parent
4a4c78bf64
commit
1acefc679d
50
app/main.py
50
app/main.py
|
@ -64,22 +64,13 @@ _RESIZED_CACHE: MutableMapping[tuple[str, int], tuple[bytes, str, Any]] = LFUCac
|
|||
# TODO(ts):
|
||||
#
|
||||
# Next:
|
||||
# - inbox/outbox admin
|
||||
# - no counters anymore?
|
||||
# - allow to show tags in the menu
|
||||
# - 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
|
||||
# - hash config/profile to detect when to send Update actor
|
||||
#
|
||||
# - [ ] block support
|
||||
# - [ ] make the media proxy authenticated
|
||||
# - [ ] prevent SSRF (urlutils from little-boxes)
|
||||
# - [ ] Dockerization
|
||||
# - [ ] Webmentions
|
||||
# - [ ] custom emoji
|
||||
# - [ ] poll/questions support
|
||||
# - [ ] cleanup tasks
|
||||
|
||||
app = FastAPI(docs_url=None, redoc_url=None)
|
||||
|
@ -564,25 +555,56 @@ async def tag_by_name(
|
|||
if not tagged_count:
|
||||
raise HTTPException(status_code=404)
|
||||
|
||||
outbox_objects = await db_session.execute(
|
||||
if is_activitypub_requested(request):
|
||||
outbox_object_ids = await db_session.execute(
|
||||
select(models.OutboxObject.ap_id)
|
||||
.join(models.TaggedOutboxObject)
|
||||
.join(
|
||||
models.TaggedOutboxObject,
|
||||
models.TaggedOutboxObject.outbox_object_id == models.OutboxObject.id,
|
||||
)
|
||||
.where(*where)
|
||||
.order_by(models.OutboxObject.ap_published_at.desc())
|
||||
.limit(20)
|
||||
)
|
||||
# TODO(ts): implement HTML version
|
||||
# if is_activitypub_requested(request):
|
||||
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_objects],
|
||||
"orderedItems": [
|
||||
outbox_object.ap_id for outbox_object in outbox_object_ids
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
outbox_objects_result = await db_session.scalars(
|
||||
select(models.OutboxObject)
|
||||
.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())
|
||||
.limit(20)
|
||||
)
|
||||
outbox_objects = outbox_objects_result.unique().all()
|
||||
|
||||
return await templates.render_template(
|
||||
db_session,
|
||||
request,
|
||||
"index.html",
|
||||
{
|
||||
"request": request,
|
||||
"objects": outbox_objects,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@app.get("/e/{name}")
|
||||
def emoji_by_name(name: str) -> ActivityPubResponse:
|
||||
|
|
|
@ -2,6 +2,9 @@ from fastapi.testclient import TestClient
|
|||
from sqlalchemy.orm import Session
|
||||
|
||||
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(
|
||||
|
@ -11,3 +14,43 @@ def test_tags__no_tags(
|
|||
response = client.get("/t/nope", headers={"Accept": ap.AP_CONTENT_TYPE})
|
||||
|
||||
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]
|
||||
|
|
Loading…
Reference in New Issue