Replaces the per-file inviteToSlack helpers with a single auto-flag call. Self-serve activation paths now check for pre-existing workspace membership (silent on miss) instead of attempting an admin-only invite. - helcim/subscription.post.js: removed local inviteToSlack; both free- and paid-tier activation branches now call the helper, then notifyNewMember with the canonical 'manual_invitation_required' arg. - members/create.post.js: same shape — helper + canonical notify arg. - invite/accept.post.js (free-tier branch): added the helper call after member creation. Free-tier had no prior Slack call (audit confirmed); paid-tier remains untouched and activates via the Helcim webhook. Admin-created and CSV-imported members intentionally do NOT call the helper — admins flip the flag manually after sending the invite. Test stub for autoFlagPreExistingSlackAccess added to server setup.
84 lines
No EOL
2.4 KiB
JavaScript
84 lines
No EOL
2.4 KiB
JavaScript
// server/api/members/create.post.js
|
|
import Member from '../../models/member.js'
|
|
import { connectDB } from '../../utils/mongoose.js'
|
|
import { getSlackService } from '../../utils/slack.ts'
|
|
import { validateBody } from '../../utils/validateBody.js'
|
|
import { memberCreateSchema } from '../../utils/schemas.js'
|
|
import { sendWelcomeEmail } from '../../utils/resend.js'
|
|
import { assignMemberNumber } from '../../utils/memberNumber.js'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
// Ensure database is connected
|
|
await connectDB()
|
|
|
|
const validatedData = await validateBody(event, memberCreateSchema)
|
|
|
|
try {
|
|
// Check if member already exists
|
|
const existingMember = await Member.findOne({ email: validatedData.email })
|
|
if (existingMember) {
|
|
throw createError({
|
|
statusCode: 409,
|
|
statusMessage: 'A member with this email already exists'
|
|
})
|
|
}
|
|
|
|
const member = new Member(validatedData)
|
|
await member.save()
|
|
|
|
await assignMemberNumber(member._id)
|
|
|
|
// Log member joined
|
|
logActivity(member._id, 'member_joined', {
|
|
circle: member.circle
|
|
}, { timestamp: member.createdAt })
|
|
|
|
// Auto-flag pre-existing Slack workspace members; admin manually invites the rest.
|
|
await autoFlagPreExistingSlackAccess(member)
|
|
try {
|
|
const slackService = getSlackService()
|
|
if (slackService) {
|
|
await slackService.notifyNewMember(
|
|
member.name,
|
|
member.email,
|
|
member.circle,
|
|
member.contributionAmount,
|
|
'manual_invitation_required'
|
|
)
|
|
}
|
|
} catch (err) {
|
|
console.error('[slack] notifyNewMember failed:', err)
|
|
}
|
|
|
|
// Send welcome email (non-blocking)
|
|
try {
|
|
await sendWelcomeEmail(member)
|
|
logActivity(member._id, 'email_sent', {
|
|
emailType: 'welcome',
|
|
subject: 'Welcome to Ghost Guild'
|
|
})
|
|
} catch (emailError) {
|
|
console.error('Failed to send welcome email:', emailError)
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
member: {
|
|
id: member._id,
|
|
email: member.email,
|
|
name: member.name,
|
|
circle: member.circle,
|
|
contributionAmount: member.contributionAmount,
|
|
status: member.status
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (error.statusCode) {
|
|
throw error
|
|
}
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Member creation failed'
|
|
})
|
|
}
|
|
}) |