-
Notifications
You must be signed in to change notification settings - Fork 722
❇️ 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
base: main
Are you sure you want to change the base?
❇️ Ozone events timeline #3927
Conversation
"type": "string", | ||
"knownValues": ["account", "record", "chat"] | ||
}, | ||
"eventType": { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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'
.
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 | ||
} | ||
} |
There was a problem hiding this comment.
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": { |
There was a problem hiding this comment.
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] |
There was a problem hiding this comment.
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.
if (!events[day]) { | ||
events[day] = {} | ||
} | ||
|
||
events[day][event.operation.type] = | ||
(events[day][event.operation.type] || 0) + 1 |
There was a problem hiding this comment.
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:
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]++ |
const { data } = await ctx.pdsAgent.tools.ozone.hosting.getAccountHistory( | ||
{ did }, | ||
auth, | ||
) | ||
cursor = data.cursor |
There was a problem hiding this comment.
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') { |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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:
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)`;
}
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!
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.