Implement member management enhancements; add bulk import functionality and duplicate checking based on geburtsdatum. Update API to support new fields and improve error handling for member data submissions. Refactor member-related components for better user experience and data validation.
This commit is contained in:
192
server/api/members/bulk.post.js
Normal file
192
server/api/members/bulk.post.js
Normal file
@@ -0,0 +1,192 @@
|
||||
import { verifyToken, getUserById } from '../../utils/auth.js'
|
||||
import { readMembers, writeMembers, normalizeDate } from '../../utils/members.js'
|
||||
import { randomUUID } from 'crypto'
|
||||
|
||||
// Helper function to check for duplicates in a list (with optional exclude)
|
||||
function findDuplicateMemberInList(members, firstName, lastName, geburtsdatum, excludeId = null) {
|
||||
const normalizedFirstName = (firstName || '').trim().toLowerCase()
|
||||
const normalizedLastName = (lastName || '').trim().toLowerCase()
|
||||
const normalizedDate = normalizeDate(geburtsdatum)
|
||||
|
||||
return members.find(m => {
|
||||
if (excludeId && m.id === excludeId) return false
|
||||
const mFirstName = (m.firstName || '').trim().toLowerCase()
|
||||
const mLastName = (m.lastName || '').trim().toLowerCase()
|
||||
const mDate = normalizeDate(m.geburtsdatum)
|
||||
|
||||
return mFirstName === normalizedFirstName &&
|
||||
mLastName === normalizedLastName &&
|
||||
mDate === normalizedDate &&
|
||||
mDate !== ''
|
||||
})
|
||||
}
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
// Support both Cookie and Authorization Header
|
||||
let token = getCookie(event, 'auth_token')
|
||||
|
||||
if (!token) {
|
||||
const authHeader = getHeader(event, 'authorization')
|
||||
if (authHeader && authHeader.startsWith('Bearer ')) {
|
||||
token = authHeader.substring(7)
|
||||
}
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
message: 'Nicht authentifiziert. Bitte Token im Cookie oder Authorization-Header bereitstellen.'
|
||||
})
|
||||
}
|
||||
|
||||
const decoded = verifyToken(token)
|
||||
|
||||
if (!decoded) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
message: 'Ungültiges Token.'
|
||||
})
|
||||
}
|
||||
|
||||
const user = await getUserById(decoded.id)
|
||||
|
||||
if (!user) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
message: 'Benutzer nicht gefunden.'
|
||||
})
|
||||
}
|
||||
|
||||
// Only admin and vorstand can add members in bulk
|
||||
if (user.role !== 'admin' && user.role !== 'vorstand') {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
message: 'Keine Berechtigung zum Bulk-Import von Mitgliedern. Erforderlich: admin oder vorstand Rolle.'
|
||||
})
|
||||
}
|
||||
|
||||
const body = await readBody(event)
|
||||
const { members: membersToImport } = body
|
||||
|
||||
if (!Array.isArray(membersToImport) || membersToImport.length === 0) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: 'Bitte senden Sie ein Array von Mitgliedern im Feld "members".'
|
||||
})
|
||||
}
|
||||
|
||||
// Validate all members before processing
|
||||
const validationErrors = []
|
||||
membersToImport.forEach((member, index) => {
|
||||
if (!member.firstName || !member.lastName) {
|
||||
validationErrors.push(`Zeile ${index + 1}: Vorname und Nachname sind erforderlich.`)
|
||||
}
|
||||
if (!member.geburtsdatum) {
|
||||
validationErrors.push(`Zeile ${index + 1}: Geburtsdatum ist erforderlich.`)
|
||||
}
|
||||
})
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: `Validierungsfehler:\n${validationErrors.join('\n')}`
|
||||
})
|
||||
}
|
||||
|
||||
// Read existing members
|
||||
const existingMembers = await readMembers()
|
||||
|
||||
const results = {
|
||||
success: [],
|
||||
duplicates: [],
|
||||
errors: []
|
||||
}
|
||||
|
||||
// Process each member
|
||||
for (let i = 0; i < membersToImport.length; i++) {
|
||||
const memberData = membersToImport[i]
|
||||
|
||||
try {
|
||||
// Check for duplicates in existing members
|
||||
const duplicateInExisting = findDuplicateMemberInList(
|
||||
existingMembers,
|
||||
memberData.firstName,
|
||||
memberData.lastName,
|
||||
memberData.geburtsdatum
|
||||
)
|
||||
|
||||
if (duplicateInExisting) {
|
||||
results.duplicates.push({
|
||||
index: i + 1,
|
||||
member: memberData,
|
||||
reason: `Existiert bereits (ID: ${duplicateInExisting.id})`
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for duplicates within the import batch
|
||||
const duplicateInBatch = findDuplicateMemberInList(
|
||||
membersToImport.slice(0, i),
|
||||
memberData.firstName,
|
||||
memberData.lastName,
|
||||
memberData.geburtsdatum
|
||||
)
|
||||
|
||||
if (duplicateInBatch) {
|
||||
results.duplicates.push({
|
||||
index: i + 1,
|
||||
member: memberData,
|
||||
reason: 'Duplikat innerhalb des Imports'
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
// Add new member
|
||||
const newMember = {
|
||||
...memberData,
|
||||
id: memberData.id || randomUUID()
|
||||
}
|
||||
|
||||
existingMembers.push(newMember)
|
||||
results.success.push({
|
||||
index: i + 1,
|
||||
member: newMember
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
results.errors.push({
|
||||
index: i + 1,
|
||||
member: memberData,
|
||||
error: error.message || 'Unbekannter Fehler'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Save all successfully imported members
|
||||
if (results.success.length > 0) {
|
||||
await writeMembers(existingMembers)
|
||||
}
|
||||
|
||||
return {
|
||||
success: results.success.length > 0,
|
||||
summary: {
|
||||
total: membersToImport.length,
|
||||
imported: results.success.length,
|
||||
duplicates: results.duplicates.length,
|
||||
errors: results.errors.length
|
||||
},
|
||||
results: results
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Bulk-Import von Mitgliedern:', error)
|
||||
if (error.statusCode) {
|
||||
throw error
|
||||
}
|
||||
throw createError({
|
||||
statusCode: error.statusCode || 500,
|
||||
message: error.message || 'Fehler beim Bulk-Import von Mitgliedern.'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user