Test
Dieser Commit ist enthalten in:
445
backend/scripts/seed-demo-data.ts
Normale Datei
445
backend/scripts/seed-demo-data.ts
Normale Datei
@ -0,0 +1,445 @@
|
||||
import dotenv from 'dotenv'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { initializeSecureDatabase, encryptedDb, db } from '../src/config/secureDatabase'
|
||||
import { initializeDatabase } from '../src/config/database'
|
||||
import { FieldEncryption } from '../src/services/encryption'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
initializeSecureDatabase()
|
||||
initializeDatabase()
|
||||
|
||||
type SampleSkill = {
|
||||
id: string
|
||||
level: string
|
||||
verified?: boolean
|
||||
}
|
||||
|
||||
type SampleEmployee = {
|
||||
firstName: string
|
||||
lastName: string
|
||||
username: string
|
||||
email: string
|
||||
role: 'admin' | 'superuser' | 'user'
|
||||
department: string
|
||||
position: string
|
||||
employeeNumber: string
|
||||
phone: string
|
||||
mobile?: string
|
||||
office?: string
|
||||
availability?: string
|
||||
skills: SampleSkill[]
|
||||
languages?: { language: string; proficiency: string; certified?: number }[]
|
||||
clearance?: { level: string; validUntil: string; issuedDate: string }
|
||||
}
|
||||
|
||||
const SAMPLE_EMPLOYEES: SampleEmployee[] = [
|
||||
{
|
||||
firstName: 'Anna',
|
||||
lastName: 'Meyer',
|
||||
username: 'a.meyer',
|
||||
email: 'anna.meyer@example.local',
|
||||
role: 'admin',
|
||||
department: 'Leitungsstab',
|
||||
position: 'Leitung PMO',
|
||||
employeeNumber: 'SM-001',
|
||||
phone: '+49 201 123-1001',
|
||||
mobile: '+49 171 2001001',
|
||||
office: 'LS-2.14',
|
||||
availability: 'available',
|
||||
skills: [
|
||||
{ id: 'communication.languages.de', level: '9', verified: true },
|
||||
{ id: 'analytical.data_analysis.statistics', level: '7' },
|
||||
{ id: 'technical.programming.python', level: '6' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C2', certified: 1 },
|
||||
{ language: 'en', proficiency: 'C1' }
|
||||
],
|
||||
clearance: {
|
||||
level: 'Ü3',
|
||||
validUntil: '2027-06-30',
|
||||
issuedDate: '2022-07-01'
|
||||
}
|
||||
},
|
||||
{
|
||||
firstName: 'Daniel',
|
||||
lastName: 'Schulz',
|
||||
username: 'd.schulz',
|
||||
email: 'daniel.schulz@example.local',
|
||||
role: 'superuser',
|
||||
department: 'Cybercrime',
|
||||
position: 'Teamleiter Digitale Forensik',
|
||||
employeeNumber: 'SM-002',
|
||||
phone: '+49 201 123-1002',
|
||||
mobile: '+49 171 2001002',
|
||||
office: 'CC-3.04',
|
||||
availability: 'available',
|
||||
skills: [
|
||||
{ id: 'technical.security.forensics', level: '8', verified: true },
|
||||
{ id: 'analytical.intelligence.threat', level: '6' },
|
||||
{ id: 'technical.programming.python', level: '5' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C1' },
|
||||
{ language: 'en', proficiency: 'B2' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Miriam',
|
||||
lastName: 'Koch',
|
||||
username: 'm.koch',
|
||||
email: 'miriam.koch@example.local',
|
||||
role: 'user',
|
||||
department: 'Kriminalprävention',
|
||||
position: 'Referentin Prävention',
|
||||
employeeNumber: 'SM-003',
|
||||
phone: '+49 201 123-1003',
|
||||
availability: 'busy',
|
||||
skills: [
|
||||
{ id: 'communication.interpersonal.presentation', level: '7' },
|
||||
{ id: 'operational.investigation.interrogation', level: '4' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C2' },
|
||||
{ language: 'fr', proficiency: 'B2' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Jonas',
|
||||
lastName: 'Becker',
|
||||
username: 'j.becker',
|
||||
email: 'jonas.becker@example.local',
|
||||
role: 'user',
|
||||
department: 'Cybercrime',
|
||||
position: 'Analyst OSINT',
|
||||
employeeNumber: 'SM-004',
|
||||
phone: '+49 201 123-1004',
|
||||
skills: [
|
||||
{ id: 'analytical.intelligence.osint', level: '8', verified: true },
|
||||
{ id: 'analytical.intelligence.pattern', level: '6' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C1' },
|
||||
{ language: 'en', proficiency: 'C1' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Leonie',
|
||||
lastName: 'Graf',
|
||||
username: 'l.graf',
|
||||
email: 'leonie.graf@example.local',
|
||||
role: 'superuser',
|
||||
department: 'Organisierte Kriminalität',
|
||||
position: 'Ermittlerin',
|
||||
employeeNumber: 'SM-005',
|
||||
phone: '+49 201 123-1005',
|
||||
availability: 'available',
|
||||
skills: [
|
||||
{ id: 'operational.investigation.surveillance', level: '7' },
|
||||
{ id: 'operational.tactical.planning', level: '6' }
|
||||
],
|
||||
clearance: {
|
||||
level: 'Ü2',
|
||||
validUntil: '2026-05-15',
|
||||
issuedDate: '2021-05-16'
|
||||
}
|
||||
},
|
||||
{
|
||||
firstName: 'Yusuf',
|
||||
lastName: 'Öztürk',
|
||||
username: 'y.oeztuerk',
|
||||
email: 'yusuf.oeztuerk@example.local',
|
||||
role: 'user',
|
||||
department: 'Cybercrime',
|
||||
position: 'Incident Responder',
|
||||
employeeNumber: 'SM-006',
|
||||
phone: '+49 201 123-1006',
|
||||
skills: [
|
||||
{ id: 'technical.security.siem', level: '7' },
|
||||
{ id: 'technical.security.malware', level: '5' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C1' },
|
||||
{ language: 'tr', proficiency: 'C1' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Klara',
|
||||
lastName: 'Heinrich',
|
||||
username: 'k.heinrich',
|
||||
email: 'klara.heinrich@example.local',
|
||||
role: 'user',
|
||||
department: 'Kriminalprävention',
|
||||
position: 'Datenanalystin',
|
||||
employeeNumber: 'SM-007',
|
||||
phone: '+49 201 123-1007',
|
||||
skills: [
|
||||
{ id: 'analytical.data_analysis.statistics', level: '8' },
|
||||
{ id: 'analytical.data_analysis.financial', level: '6' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Sebastian',
|
||||
lastName: 'Ulrich',
|
||||
username: 's.ulrich',
|
||||
email: 'sebastian.ulrich@example.local',
|
||||
role: 'user',
|
||||
department: 'Cybercrime',
|
||||
position: 'Digitaler Spurensicherer',
|
||||
employeeNumber: 'SM-008',
|
||||
phone: '+49 201 123-1008',
|
||||
availability: 'offline',
|
||||
skills: [
|
||||
{ id: 'operational.investigation.evidence', level: '7', verified: true },
|
||||
{ id: 'technical.security.forensics', level: '6' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Jana',
|
||||
lastName: 'Reuter',
|
||||
username: 'j.reuter',
|
||||
email: 'jana.reuter@example.local',
|
||||
role: 'superuser',
|
||||
department: 'Nachrichtendienstliche Analyse',
|
||||
position: 'Analystin Gefährdungsbewertung',
|
||||
employeeNumber: 'SM-009',
|
||||
phone: '+49 201 123-1009',
|
||||
skills: [
|
||||
{ id: 'analytical.intelligence.threat', level: '8', verified: true },
|
||||
{ id: 'analytical.intelligence.risk', level: '7' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C2' },
|
||||
{ language: 'en', proficiency: 'C1' },
|
||||
{ language: 'ru', proficiency: 'B2' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Harald',
|
||||
lastName: 'Pohl',
|
||||
username: 'h.pohl',
|
||||
email: 'harald.pohl@example.local',
|
||||
role: 'user',
|
||||
department: 'Mobiles Einsatzkommando',
|
||||
position: 'Einsatzführer',
|
||||
employeeNumber: 'SM-010',
|
||||
phone: '+49 201 123-1010',
|
||||
availability: 'available',
|
||||
skills: [
|
||||
{ id: 'operational.tactical.protection', level: '8' },
|
||||
{ id: 'certifications.weapons.sniper', level: '7', verified: true }
|
||||
],
|
||||
clearance: {
|
||||
level: 'Ü2',
|
||||
validUntil: '2025-12-31',
|
||||
issuedDate: '2020-01-01'
|
||||
}
|
||||
},
|
||||
{
|
||||
firstName: 'Melanie',
|
||||
lastName: 'Franke',
|
||||
username: 'm.franke',
|
||||
email: 'melanie.franke@example.local',
|
||||
role: 'user',
|
||||
department: 'Kriminalprävention',
|
||||
position: 'Projektmanagerin Prävention',
|
||||
employeeNumber: 'SM-011',
|
||||
phone: '+49 201 123-1011',
|
||||
skills: [
|
||||
{ id: 'communication.interpersonal.teamwork', level: '8' },
|
||||
{ id: 'communication.interpersonal.conflict', level: '6' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Farid',
|
||||
lastName: 'Rahmani',
|
||||
username: 'f.rahmani',
|
||||
email: 'farid.rahmani@example.local',
|
||||
role: 'user',
|
||||
department: 'Cybercrime',
|
||||
position: 'Entwickler Automatisierung',
|
||||
employeeNumber: 'SM-012',
|
||||
phone: '+49 201 123-1012',
|
||||
skills: [
|
||||
{ id: 'technical.programming.javascript', level: '7' },
|
||||
{ id: 'technical.programming.python', level: '8' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'B2' },
|
||||
{ language: 'fa', proficiency: 'C1' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Lena',
|
||||
lastName: 'Zimmer',
|
||||
username: 'l.zimmer',
|
||||
email: 'lena.zimmer@example.local',
|
||||
role: 'user',
|
||||
department: 'Kriminalprävention',
|
||||
position: 'Datenvisualisierung',
|
||||
employeeNumber: 'SM-013',
|
||||
phone: '+49 201 123-1013',
|
||||
availability: 'busy',
|
||||
skills: [
|
||||
{ id: 'analytical.data_analysis.network_analysis', level: '6' },
|
||||
{ id: 'communication.presentation.presentation', level: '5' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Erik',
|
||||
lastName: 'Brandt',
|
||||
username: 'e.brandt',
|
||||
email: 'erik.brandt@example.local',
|
||||
role: 'superuser',
|
||||
department: 'Nachrichtendienstliche Analyse',
|
||||
position: 'Projektleiter Prognosemodelle',
|
||||
employeeNumber: 'SM-014',
|
||||
phone: '+49 201 123-1014',
|
||||
skills: [
|
||||
{ id: 'analytical.intelligence.forecasting', level: '8' },
|
||||
{ id: 'analytical.data_analysis.statistics', level: '7' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C1' },
|
||||
{ language: 'en', proficiency: 'C1' }
|
||||
]
|
||||
},
|
||||
{
|
||||
firstName: 'Sofia',
|
||||
lastName: 'Lindner',
|
||||
username: 's.lindner',
|
||||
email: 'sofia.lindner@example.local',
|
||||
role: 'user',
|
||||
department: 'Cybercrime',
|
||||
position: 'Malware Analystin',
|
||||
employeeNumber: 'SM-015',
|
||||
phone: '+49 201 123-1015',
|
||||
skills: [
|
||||
{ id: 'technical.security.malware', level: '8' },
|
||||
{ id: 'technical.security.crypto', level: '6' }
|
||||
],
|
||||
languages: [
|
||||
{ language: 'de', proficiency: 'C1' },
|
||||
{ language: 'en', proficiency: 'B2' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const PASSWORD = 'test123'
|
||||
|
||||
const deleteExistingByUsername = db.prepare('DELETE FROM users WHERE username = ?')
|
||||
const deleteEmployeeById = db.prepare('DELETE FROM employees WHERE id = ?')
|
||||
const selectUserByUsername = db.prepare('SELECT id, employee_id FROM users WHERE username = ?')
|
||||
const deleteEmployeeSkills = db.prepare('DELETE FROM employee_skills WHERE employee_id = ?')
|
||||
const deleteLanguageSkills = db.prepare('DELETE FROM language_skills WHERE employee_id = ?')
|
||||
|
||||
const insertSkill = db.prepare(`
|
||||
INSERT INTO employee_skills (
|
||||
employee_id, skill_id, level, verified, verified_by, verified_date
|
||||
) VALUES (?, ?, ?, ?, ?, ?)
|
||||
`)
|
||||
|
||||
const insertLanguage = db.prepare(`
|
||||
INSERT INTO language_skills (
|
||||
id, employee_id, language, proficiency, certified, certificate_type, is_native, can_interpret
|
||||
) VALUES (?, ?, ?, ?, ?, ?, 0, 0)
|
||||
`)
|
||||
|
||||
const insertUser = db.prepare(`
|
||||
INSERT INTO users (
|
||||
id, username, email, email_hash, password, role, employee_id, is_active, created_at, updated_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
||||
`)
|
||||
|
||||
const nowIso = () => new Date().toISOString()
|
||||
|
||||
const hashPassword = (plain: string) => bcrypt.hashSync(plain, 12)
|
||||
|
||||
function upsertEmployee(sample: SampleEmployee) {
|
||||
const existingUser = selectUserByUsername.get(sample.username) as { id: string; employee_id: string } | undefined
|
||||
|
||||
if (existingUser) {
|
||||
deleteEmployeeSkills.run(existingUser.employee_id)
|
||||
deleteLanguageSkills.run(existingUser.employee_id)
|
||||
deleteEmployeeById.run(existingUser.employee_id)
|
||||
deleteExistingByUsername.run(sample.username)
|
||||
}
|
||||
|
||||
const employeeId = uuidv4()
|
||||
const createdAt = nowIso()
|
||||
const availability = sample.availability || 'available'
|
||||
|
||||
encryptedDb.insertEmployee({
|
||||
id: employeeId,
|
||||
first_name: sample.firstName,
|
||||
last_name: sample.lastName,
|
||||
employee_number: sample.employeeNumber,
|
||||
photo: null,
|
||||
position: sample.position,
|
||||
department: sample.department,
|
||||
email: sample.email,
|
||||
phone: sample.phone,
|
||||
mobile: sample.mobile || null,
|
||||
office: sample.office || null,
|
||||
availability,
|
||||
clearance_level: sample.clearance?.level || null,
|
||||
clearance_valid_until: sample.clearance?.validUntil || null,
|
||||
clearance_issued_date: sample.clearance?.issuedDate || null,
|
||||
primary_unit_id: null,
|
||||
created_at: createdAt,
|
||||
updated_at: createdAt,
|
||||
created_by: 'system'
|
||||
})
|
||||
|
||||
const verifiedBy = sample.role === 'admin' ? 'system-admin' : 'system'
|
||||
|
||||
for (const skill of sample.skills) {
|
||||
insertSkill.run(
|
||||
employeeId,
|
||||
skill.id,
|
||||
skill.level,
|
||||
skill.verified ? 1 : 0,
|
||||
skill.verified ? verifiedBy : null,
|
||||
skill.verified ? createdAt : null
|
||||
)
|
||||
}
|
||||
|
||||
for (const language of sample.languages || []) {
|
||||
insertLanguage.run(
|
||||
uuidv4(),
|
||||
employeeId,
|
||||
language.language,
|
||||
language.proficiency,
|
||||
language.certified || 0,
|
||||
language.certified ? 'Zertifikat' : null
|
||||
)
|
||||
}
|
||||
|
||||
const userId = uuidv4()
|
||||
const encryptedEmail = FieldEncryption.encrypt(sample.email) || ''
|
||||
const emailHash = FieldEncryption.hash(sample.email)
|
||||
const hashedPassword = hashPassword(PASSWORD)
|
||||
const timestamps = nowIso()
|
||||
|
||||
insertUser.run(
|
||||
userId,
|
||||
sample.username,
|
||||
encryptedEmail,
|
||||
emailHash,
|
||||
hashedPassword,
|
||||
sample.role,
|
||||
employeeId,
|
||||
timestamps,
|
||||
timestamps
|
||||
)
|
||||
}
|
||||
|
||||
db.transaction(() => {
|
||||
for (const employee of SAMPLE_EMPLOYEES) {
|
||||
upsertEmployee(employee)
|
||||
}
|
||||
})()
|
||||
|
||||
console.log(`✅ ${SAMPLE_EMPLOYEES.length} Demo-Mitarbeiter mit Passwort "${PASSWORD}" angelegt.`)
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren