Add DMs section

This commit is contained in:
Thomas Sileo 2022-08-11 22:07:40 +02:00
parent ccd77adcb6
commit 6b8a4d94b2
3 changed files with 190 additions and 1 deletions

View file

@ -1,3 +1,5 @@
from datetime import datetime
import httpx import httpx
from fastapi import APIRouter from fastapi import APIRouter
from fastapi import Cookie from fastapi import Cookie
@ -8,7 +10,9 @@ from fastapi import UploadFile
from fastapi.exceptions import HTTPException from fastapi.exceptions import HTTPException
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
from loguru import logger from loguru import logger
from sqlalchemy import and_
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy import or_
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
@ -383,6 +387,173 @@ async def admin_inbox(
) )
@router.get("/direct_messages")
async def admin_direct_messages(
request: Request,
db_session: AsyncSession = Depends(get_db_session),
cursor: str | None = None,
) -> templates.TemplateResponse:
inbox_convos = (
(
await db_session.execute(
select(
models.InboxObject.ap_context,
models.InboxObject.actor_id,
func.count(1).label("count"),
func.max(models.InboxObject.ap_published_at).label(
"most_recent_date"
),
)
.where(
models.InboxObject.visibility == ap.VisibilityEnum.DIRECT,
models.InboxObject.ap_context.is_not(None),
)
.group_by(models.InboxObject.ap_context, models.InboxObject.actor_id)
)
)
.unique()
.all()
)
outbox_convos = (
(
await db_session.execute(
select(
models.OutboxObject.ap_context,
func.count(1).label("count"),
func.max(models.OutboxObject.ap_published_at).label(
"most_recent_date"
),
)
.where(
models.OutboxObject.visibility == ap.VisibilityEnum.DIRECT,
models.OutboxObject.ap_context.is_not(None),
)
.group_by(models.OutboxObject.ap_context)
)
)
.unique()
.all()
)
convos = {}
for inbox_convo in inbox_convos:
if inbox_convo.ap_context not in convos:
convos[inbox_convo.ap_context] = {
"actor_ids": {inbox_convo.actor_id},
"count": inbox_convo.count,
"most_recent_from_inbox": inbox_convo.most_recent_date,
"most_recent_from_outbox": datetime.min,
}
else:
convos[inbox_convo.ap_context]["actor_ids"].add(inbox_convo.actor_id)
convos[inbox_convo.ap_context]["count"] += inbox_convo.count
convos[inbox_convo.ap_context]["most_recent_from_inbox"] = max(
inbox_convo.most_recent_date,
convos[inbox_convo.ap_context]["most_recent_from_inbox"],
)
for outbox_convo in outbox_convos:
if outbox_convo.ap_context not in convos:
convos[outbox_convo.ap_context] = {
"actor_ids": set(),
"count": outbox_convo.count,
"most_recent_from_inbox": datetime.min,
"most_recent_from_outbox": outbox_convo.most_recent_date,
}
else:
convos[outbox_convo.ap_context]["count"] += outbox_convo.count
convos[outbox_convo.ap_context]["most_recent_from_outbox"] = max(
outbox_convo.most_recent_date,
convos[outbox_convo.ap_context]["most_recent_from_outbox"],
)
convos_with_last_from_inbox = []
convos_with_last_from_outbox = []
for context, convo in convos.items():
if convo["most_recent_from_inbox"] > convo["most_recent_from_outbox"]:
convos_with_last_from_inbox.append(
and_(
models.InboxObject.ap_context == context,
models.InboxObject.ap_published_at
== convo["most_recent_from_inbox"],
)
)
else:
convos_with_last_from_outbox.append(
and_(
models.OutboxObject.ap_context == context,
models.OutboxObject.ap_published_at
== convo["most_recent_from_outbox"],
)
)
last_from_inbox = (
(
await db_session.scalars(
select(models.InboxObject)
.where(or_(*convos_with_last_from_inbox))
.options(
joinedload(models.InboxObject.actor),
)
)
)
.unique()
.all()
)
last_from_outbox = (
(
await db_session.scalars(
select(models.OutboxObject)
.where(or_(*convos_with_last_from_outbox))
.options(
joinedload(models.OutboxObject.outbox_object_attachments).options(
joinedload(models.OutboxObjectAttachment.upload)
),
)
)
)
.unique()
.all()
)
threads = []
for anybox_object in sorted(
last_from_inbox + last_from_outbox,
key=lambda x: x.ap_published_at,
reverse=True,
):
convo = convos[anybox_object.ap_context]
actors = list(
(
await db_session.execute(
select(models.Actor).where(models.Actor.id.in_(convo["actor_ids"]))
)
).scalars()
)
# If this message from outbox starts a thread with no replies, look
# at the mentions
if not actors and anybox_object.is_from_outbox:
actors = ( # type: ignore
await db_session.execute(
select(models.Actor).where(
models.Actor.ap_id.in_(
mention["href"]
for mention in anybox_object.tags
if mention["type"] == "Mention"
)
)
)
).scalars()
threads.append((anybox_object, convo, actors))
return await templates.render_template(
db_session,
request,
"admin_direct_messages.html",
{
"threads": threads,
},
)
@router.get("/outbox") @router.get("/outbox")
async def admin_outbox( async def admin_outbox(
request: Request, request: Request,

View file

@ -0,0 +1,18 @@
{%- import "utils.html" as utils with context -%}
{% extends "layout.html" %}
{% block head %}
<title>{{ local_actor.display_name }} - Direct messages</title>
{% endblock %}
{% block content %}
{% for anybox_object, convo, actors in threads %}
<div class="actor-action">
With {% for actor in actors %}
<a href="">{{ actor.handle }}</a>
{% endfor %}
</div>
{{ utils.display_object(anybox_object) }}
{% endfor %}
{% endblock %}

View file

@ -26,11 +26,11 @@
<div style="margin-bottom:30px;padding: 0 20px;"> <div style="margin-bottom:30px;padding: 0 20px;">
<nav class="flexbox"> <nav class="flexbox">
<ul> <ul>
<li>Admin</li>
<li>{{ admin_link("index", "Public") }}</li> <li>{{ admin_link("index", "Public") }}</li>
<li>{{ admin_link("admin_new", "New") }}</li> <li>{{ admin_link("admin_new", "New") }}</li>
<li>{{ admin_link("admin_stream", "Stream") }}</li> <li>{{ admin_link("admin_stream", "Stream") }}</li>
<li>{{ admin_link("admin_inbox", "Inbox") }} / {{ admin_link("admin_outbox", "Outbox") }}</li> <li>{{ admin_link("admin_inbox", "Inbox") }} / {{ admin_link("admin_outbox", "Outbox") }}</li>
<li>{{ admin_link("admin_direct_messages", "DMs") }}</li>
<li>{{ admin_link("get_notifications", "Notifications") }} {% if notifications_count %}({{ notifications_count }}){% endif %}</li> <li>{{ admin_link("get_notifications", "Notifications") }} {% if notifications_count %}({{ notifications_count }}){% endif %}</li>
<li>{{ admin_link("get_lookup", "Lookup") }}</li> <li>{{ admin_link("get_lookup", "Lookup") }}</li>
<li>{{ admin_link("admin_bookmarks", "Bookmarks") }}</li> <li>{{ admin_link("admin_bookmarks", "Bookmarks") }}</li>