8000 ❇️ Ozone events timeline by foysalit · Pull Request #3927 · bluesky-social/atproto · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

❇️ Ozone events timeline #3927

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

❇️ Ozone events timeline #3927

wants to merge 3 commits into from

Conversation

foysalit
Copy link
Contributor
@foysalit foysalit commented Jun 5, 2025

Oftentimes, for relatively problematic accounts, the mod event history gets quite noisy while not painting a full picture for moderators. This PR exposes the all relevant event history (not just moderation events) in a timeline view grouped by day to help moderators quickly grasp if an account is manifesting or has manifested problematic behavior.

"type": "string",
"knownValues": ["account", "record", "chat"]
},
"eventType": {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keeping this super generic since we want to be able to blend PLC audit log, mod events and account history from entryway at the moment but also leave room for additional event types in the future.
instead of keeping this flat, we could also make this an object where primary types could be modEvent, plcLog, accountHistory and then have multiple subtypes for each type of event types?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think it's a bit difficult a. not having documentation here about which timeline event types may come down, and b. mixing different namespaces such as 'plc_operation' vs. 'tools.ozone.moderation.defs#modEventTakedown'.

I'd be pretty satisfied to keep it flat, which is nice and simple, and just continue to use tokens for all the types. E.g. 'tools.ozone.moderation.defs#timelineEventPlcOperation' and 'tools.ozone.moderation.defs#modEventTakedown'.

Comment on lines +1455 to 1473
async getAccountTimeline(did: string) {
const result = await this.db.db
.selectFrom('moderation_event')
.where('subjectDid', '=', did)
.select([
sql<string>`TO_CHAR(CAST(${sql.ref('createdAt')} AS TIMESTAMP), 'YYYY-MM-DD')`.as(
'day',
),
'subjectDid',
'subjectUri',
'action',
sql<number>`count(*)`.as('count'),
])
.groupBy(['day', 'subjectDid', 'subjectUri', 'action'])
.orderBy('day', 'desc')
.execute()
return result
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since subjectDid is fixed, does it need to be part of the select, group-by, etc? Perhaps it's there for convenience of the caller.

Also just double-checking that we're not too worried about usage of this query cause any issues. I am imagining some accounts may have many moderation events. If that is a problem, one option would be to paginate it e.g. by week.

}
]
},
"accountTimeline": {
Copy link
Collaborator
@devinivy devinivy Jun 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial reaction here is that this looks more like a timelineItem. I think of a "timeline" as being a list/sequence.

continue
}

const day = new Date(event.createdAt) 10000 .toISOString().split('T')[0]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think extracting the logic to get YYYY-MM-DD will probably make this a little more readable, and will be pretty self-documenting as to what's going on.

Comment on lines +142 to +147
if (!events[day]) {
events[day] = {}
}

events[day][event.operation.type] =
(events[day][event.operation.type] || 0) + 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks all good to me, just tossing out a stylistic idea:

Suggested change
if (!events[day]) {
events[day] = {}
}
events[day][event.operation.type] =
(events[day][event.operation.type] || 0) + 1
events[day] ??= {}
events[day][event.operation.type] ??= 0
events[day][event.operation.type]++

Comment on lines +109 to +113
const { data } = await ctx.pdsAgent.tools.ozone.hosting.getAccountHistory(
{ did },
auth,
)
cursor = data.cursor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected to see the cursor used in the request.

ToolsOzoneModerationGetAccountTimeline.AccountTimelineSummary[]
>()

if (movEventHistory.status === 'fulfilled') {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this one fails we probably want the error to surface.

.selectFrom('moderation_event')
.where('subjectDid', '=', did)
.select([
sql<string>`TO_CHAR(CAST(${sql.ref('createdAt')} AS TIMESTAMP), 'YYYY-MM-DD')`.as(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps following the same logic used in typescript to extract the date would be a nice way to keep things consistent:

Suggested change
sql<string>`TO_CHAR(CAST(${sql.ref('createdAt')} AS TIMESTAMP), 'YYYY-MM-DD')`.as(
sql<string>`SPLIT_PART(${sql.ref('createdAt')}, 'T', 1)`.as(

Could even keep these utils next to each other:

const dateFromDatetime = (date: Date) => {
  const [date] = date.toISOString().split('T')
  return date
}

const dateFromDbDatetime = (dateRef: DbRef) => {
  return sql<string>`SPLIT_PART(${dateRef}, 'T', 1)`;
}

Copy link
Collaborator
@devinivy devinivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few thoughts, looking pretty good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0