Endpoint that flips a member's slackInvited flag manually after the admin has actually sent the Slack invitation through Slack's UI. No Slack API call is made from this app. - Body validated via Zod literal-true schema (no undo path for the pilot — admins correct mistakes in the database if needed). - Idempotent: re-marking an already-invited member is a no-op, preserving the original slackInvitedAt and not duplicating the activity log entry. - Activity log: slack_invited_manually, actor = admin from requireAdmin, subject = the target member.
35 lines
1.1 KiB
JavaScript
35 lines
1.1 KiB
JavaScript
import Member from '../../../../models/member.js'
|
|
import { connectDB } from '../../../../utils/mongoose.js'
|
|
import { validateBody } from '../../../../utils/validateBody.js'
|
|
import { adminSlackStatusSchema } from '../../../../utils/schemas.js'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const admin = await requireAdmin(event)
|
|
await validateBody(event, adminSlackStatusSchema)
|
|
await connectDB()
|
|
|
|
const memberId = getRouterParam(event, 'id')
|
|
|
|
const existing = await Member.findById(memberId)
|
|
if (!existing) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'Member not found.'
|
|
})
|
|
}
|
|
|
|
// Idempotent: if already invited, no-op (preserve original slackInvitedAt, no log).
|
|
if (existing.slackInvited === true) {
|
|
return { success: true, member: existing }
|
|
}
|
|
|
|
const member = await Member.findByIdAndUpdate(
|
|
memberId,
|
|
{ slackInvited: true, slackInvitedAt: new Date() },
|
|
{ new: true, runValidators: false }
|
|
)
|
|
|
|
logActivity(memberId, 'slack_invited_manually', {}, { performedBy: admin._id })
|
|
|
|
return { success: true, member }
|
|
})
|