diff --git a/server/models/adminAlertDismissal.js b/server/models/adminAlertDismissal.js new file mode 100644 index 0000000..06d902d --- /dev/null +++ b/server/models/adminAlertDismissal.js @@ -0,0 +1,39 @@ +import mongoose from 'mongoose' + +export const 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' +] + +const adminAlertDismissalSchema = new mongoose.Schema({ + adminId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'Member', + required: true + }, + alertType: { + type: String, + enum: ADMIN_ALERT_TYPES, + required: true + }, + signature: { + type: String, + required: true + }, + dismissedAt: { + type: Date, + default: Date.now + } +}) + +adminAlertDismissalSchema.index({ adminId: 1, alertType: 1 }, { unique: true }) + +export default mongoose.models.AdminAlertDismissal || + mongoose.model('AdminAlertDismissal', adminAlertDismissalSchema) diff --git a/tests/server/models/adminAlertDismissal.test.js b/tests/server/models/adminAlertDismissal.test.js new file mode 100644 index 0000000..0cfce44 --- /dev/null +++ b/tests/server/models/adminAlertDismissal.test.js @@ -0,0 +1,43 @@ +import { describe, it, expect } from 'vitest' +import AdminAlertDismissal from '../../../server/models/adminAlertDismissal.js' + +describe('AdminAlertDismissal model', () => { + it('exposes the expected schema paths', () => { + const paths = AdminAlertDismissal.schema.paths + expect(paths.adminId).toBeDefined() + expect(paths.alertType).toBeDefined() + expect(paths.signature).toBeDefined() + expect(paths.dismissedAt).toBeDefined() + }) + + it('marks adminId, alertType, and signature as required', () => { + const paths = AdminAlertDismissal.schema.paths + expect(paths.adminId.isRequired).toBe(true) + expect(paths.alertType.isRequired).toBe(true) + expect(paths.signature.isRequired).toBe(true) + }) + + it('restricts alertType to the nine known slugs', () => { + const enumValues = AdminAlertDismissal.schema.paths.alertType.enumValues + expect(enumValues).toEqual([ + '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' + ]) + }) + + it('declares a unique compound index on adminId + alertType', () => { + const indexes = AdminAlertDismissal.schema.indexes() + const compound = indexes.find(([fields]) => + fields.adminId === 1 && fields.alertType === 1 + ) + expect(compound).toBeDefined() + expect(compound[1].unique).toBe(true) + }) +})