feat(admin): add GET /api/admin/alerts endpoint
This commit is contained in:
parent
4f7a11bcf3
commit
f0284c60b4
2 changed files with 97 additions and 0 deletions
8
server/api/admin/alerts/index.get.js
Normal file
8
server/api/admin/alerts/index.get.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { computeAllAlerts } from '../../../utils/adminAlerts.js'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const admin = await requireAdmin(event)
|
||||||
|
const adminId = admin._id.toString()
|
||||||
|
const alerts = await computeAllAlerts(adminId)
|
||||||
|
return { alerts }
|
||||||
|
})
|
||||||
89
tests/server/api/admin-alerts.test.js
Normal file
89
tests/server/api/admin-alerts.test.js
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||||
|
import { readFileSync } from 'node:fs'
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
|
||||||
|
vi.mock('../../../server/utils/adminAlerts.js', () => ({
|
||||||
|
computeAllAlerts: vi.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
vi.mock('../../../server/models/adminAlertDismissal.js', () => ({
|
||||||
|
default: {
|
||||||
|
findOneAndUpdate: vi.fn()
|
||||||
|
},
|
||||||
|
ADMIN_ALERT_TYPES: [
|
||||||
|
'slack_invite_failed',
|
||||||
|
'no_slack_handle_week',
|
||||||
|
'stuck_pending_payment',
|
||||||
|
'member_suspended',
|
||||||
|
'preregistrant_selected_not_invited',
|
||||||
|
'preregistrant_expired',
|
||||||
|
'event_draft_imminent',
|
||||||
|
'event_near_capacity',
|
||||||
|
'tag_suggestions_pending'
|
||||||
|
]
|
||||||
|
}))
|
||||||
|
|
||||||
|
vi.mock('../../../server/utils/mongoose.js', () => ({
|
||||||
|
connectDB: vi.fn()
|
||||||
|
}))
|
||||||
|
|
||||||
|
import getHandler from '../../../server/api/admin/alerts/index.get.js'
|
||||||
|
import { computeAllAlerts } from '../../../server/utils/adminAlerts.js'
|
||||||
|
import { createMockEvent } from '../helpers/createMockEvent.js'
|
||||||
|
|
||||||
|
describe('GET /api/admin/alerts', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks()
|
||||||
|
requireAdmin.mockResolvedValue({ _id: { toString: () => 'admin-1' } })
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('source inspection', () => {
|
||||||
|
const source = readFileSync(
|
||||||
|
resolve(import.meta.dirname, '../../../server/api/admin/alerts/index.get.js'),
|
||||||
|
'utf-8'
|
||||||
|
)
|
||||||
|
it('calls requireAdmin before any business logic', () => {
|
||||||
|
const adminIdx = source.indexOf('requireAdmin(event)')
|
||||||
|
const computeIdx = source.indexOf('computeAllAlerts(')
|
||||||
|
expect(adminIdx).toBeGreaterThan(-1)
|
||||||
|
expect(computeIdx).toBeGreaterThan(-1)
|
||||||
|
expect(adminIdx).toBeLessThan(computeIdx)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns the active alerts for the current admin', async () => {
|
||||||
|
computeAllAlerts.mockResolvedValue([
|
||||||
|
{
|
||||||
|
type: 'slack_invite_failed',
|
||||||
|
severity: 'critical',
|
||||||
|
title: 'Slack invites failed',
|
||||||
|
count: 1,
|
||||||
|
items: [{ id: 'm1', label: 'Alex', sublabel: 'alex@example.com', href: '/admin/members/m1' }],
|
||||||
|
signature: 'abc'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const event = createMockEvent({ method: 'GET', path: '/api/admin/alerts' })
|
||||||
|
const result = await getHandler(event)
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
alerts: [
|
||||||
|
{
|
||||||
|
type: 'slack_invite_failed',
|
||||||
|
severity: 'critical',
|
||||||
|
title: 'Slack invites failed',
|
||||||
|
count: 1,
|
||||||
|
items: [{ id: 'm1', label: 'Alex', sublabel: 'alex@example.com', href: '/admin/members/m1' }],
|
||||||
|
signature: 'abc'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
expect(computeAllAlerts).toHaveBeenCalledWith('admin-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects non-admin requests', async () => {
|
||||||
|
requireAdmin.mockRejectedValue(createError({ statusCode: 403, statusMessage: 'Forbidden' }))
|
||||||
|
const event = createMockEvent({ method: 'GET', path: '/api/admin/alerts' })
|
||||||
|
await expect(getHandler(event)).rejects.toMatchObject({ statusCode: 403 })
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Add table
Add a link
Reference in a new issue