Repository navigation
feat: add audit logging to avatar, calendar, workflow, task status & channel routes #778
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { canUserViewPage, canUserEditPage } from '@pagespace/lib/server'; | |
| import { loggers } from '@pagespace/lib/server'; | ||
| import { createSignedBroadcastHeaders } from '@pagespace/lib/broadcast-auth'; | ||
| import { broadcastInboxEvent } from '@/lib/websocket/socket-utils'; | ||
| import { getActorInfo, logMessageActivity } from '@pagespace/lib/monitoring/activity-logger'; | ||
|
|
||
| // Type for attachment metadata stored in the database | ||
| interface AttachmentMeta { | ||
|
|
@@ -167,6 +168,16 @@ export async function POST(req: Request, { params }: { params: Promise<{ pageId: | |
| set: { lastReadAt: new Date() }, | ||
| }); | ||
|
|
||
| // Audit logging (fire-and-forget) | ||
| getActorInfo(userId).then(actorInfo => { | ||
| logMessageActivity(userId, 'create', { | ||
| id: createdMessage.id, | ||
| pageId, | ||
| driveId: null, | ||
| conversationType: 'channel', | ||
| }, actorInfo); | ||
| }).catch(() => {}); | ||
|
Comment on lines
+171
to
+179
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pass the real drive context in message audit logs. At Line 176, 💡 Suggested fix- // Audit logging (fire-and-forget)
+ // Audit logging (fire-and-forget) - include actual drive context
getActorInfo(userId).then(actorInfo => {
logMessageActivity(userId, 'create', {
id: createdMessage.id,
pageId,
- driveId: null,
+ driveId: channel?.driveId ?? null,
conversationType: 'channel',
}, actorInfo);
}).catch(() => {});If 🤖 Prompt for AI Agents |
||
|
|
||
| const newMessage = await db.query.channelMessages.findFirst({ | ||
| where: eq(channelMessages.id, createdMessage.id), | ||
| with: { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ import { DEFAULT_TASK_STATUSES } from '@pagespace/db'; | |
| import { authenticateRequestWithOptions, isAuthError, checkMCPPageScope } from '@/lib/auth'; | ||
| import { canUserEditPage, canUserViewPage } from '@pagespace/lib/server'; | ||
| import { broadcastTaskEvent } from '@/lib/websocket'; | ||
| import { getActorInfo, logActivity } from '@pagespace/lib/monitoring/activity-logger'; | ||
|
|
||
| const AUTH_OPTIONS_READ = { allow: ['session', 'mcp'] as const, requireCSRF: false }; | ||
| const AUTH_OPTIONS_WRITE = { allow: ['session', 'mcp'] as const, requireCSRF: true }; | ||
|
|
@@ -175,6 +176,20 @@ export async function POST( | |
| data: { statusConfigAdded: newConfig }, | ||
| }); | ||
|
|
||
| // Audit logging (fire-and-forget) | ||
| getActorInfo(userId).then(actorInfo => { | ||
| logActivity({ | ||
| userId, | ||
| ...actorInfo, | ||
| operation: 'create', | ||
| resourceType: 'page', | ||
| resourceId: pageId, | ||
| driveId: null, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
These task-status audit logs are also written with Useful? React with 👍 / 👎. |
||
| pageId, | ||
| metadata: { featureType: 'task_status', statusName: newConfig.name, statusSlug: newConfig.slug }, | ||
| }).catch(() => {}); | ||
| }).catch(() => {}); | ||
|
|
||
| return NextResponse.json(newConfig, { status: 201 }); | ||
| } | ||
|
|
||
|
|
@@ -262,6 +277,20 @@ export async function PUT( | |
| data: { statusConfigsUpdated: updatedConfigs }, | ||
| }); | ||
|
|
||
| // Audit logging (fire-and-forget) | ||
| getActorInfo(userId).then(actorInfo => { | ||
| logActivity({ | ||
| userId, | ||
| ...actorInfo, | ||
| operation: 'update', | ||
| resourceType: 'page', | ||
| resourceId: pageId, | ||
| driveId: null, | ||
| pageId, | ||
| metadata: { featureType: 'task_status', statusCount: statuses.length }, | ||
| }).catch(() => {}); | ||
| }).catch(() => {}); | ||
|
|
||
| return NextResponse.json({ statusConfigs: updatedConfigs }); | ||
| } | ||
|
|
||
|
|
@@ -388,5 +417,24 @@ export async function DELETE( | |
| }, | ||
| }); | ||
|
|
||
| // Audit logging (fire-and-forget) | ||
| getActorInfo(userId).then(actorInfo => { | ||
| logActivity({ | ||
| userId, | ||
| ...actorInfo, | ||
| operation: 'delete', | ||
| resourceType: 'page', | ||
| resourceId: pageId, | ||
| driveId: null, | ||
| pageId, | ||
| metadata: { | ||
| featureType: 'task_status', | ||
| deletedStatus: statusToDelete.slug, | ||
| migratedTo: migrateToSlug, | ||
| migratedCount: tasksWithStatus.length, | ||
| }, | ||
| }).catch(() => {}); | ||
| }).catch(() => {}); | ||
|
|
||
| return NextResponse.json({ success: true }); | ||
| } | ||
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 new audit entry is recorded with
driveId: null, so channel message activity is detached from its actual drive. Drive-scoped activity queries filter onactivityLogs.driveId(apps/web/src/app/api/activities/route.tsuseseq(activityLogs.driveId, params.driveId)in drive context), which means these records are omitted from drive audit/history views; the samedriveId: nullpattern added in the reactions route has the same effect. It also suppresses event-triggered workflows becauseemitWorkflowEventreturns early whenevent.driveIdis missing (apps/web/src/lib/workflows/event-trigger.ts).Useful? React with 👍 / 👎.