Ich habe gestern vergessen zu pushen
Dieser Commit ist enthalten in:
@ -83,13 +83,13 @@ export const encryptedDb = {
|
||||
|
||||
return db.prepare(`
|
||||
INSERT INTO employees (
|
||||
id, first_name, last_name, employee_number, photo, position,
|
||||
id, first_name, last_name, employee_number, photo, position, official_title,
|
||||
department, email, email_hash, phone, phone_hash, mobile, office, availability,
|
||||
clearance_level, clearance_valid_until, clearance_issued_date,
|
||||
primary_unit_id,
|
||||
created_at, updated_at, created_by
|
||||
) VALUES (
|
||||
@id, @first_name, @last_name, @employee_number, @photo, @position,
|
||||
@id, @first_name, @last_name, @employee_number, @photo, @position, @official_title,
|
||||
@department, @email, @email_hash, @phone, @phone_hash, @mobile, @office, @availability,
|
||||
@clearance_level, @clearance_valid_until, @clearance_issued_date,
|
||||
@primary_unit_id,
|
||||
@ -109,6 +109,7 @@ export const encryptedDb = {
|
||||
// Decrypt sensitive fields
|
||||
return {
|
||||
...employee,
|
||||
official_title: employee.official_title,
|
||||
email: FieldEncryption.decrypt(employee.email),
|
||||
phone: FieldEncryption.decrypt(employee.phone),
|
||||
mobile: FieldEncryption.decrypt(employee.mobile),
|
||||
@ -136,6 +137,7 @@ export const encryptedDb = {
|
||||
|
||||
return {
|
||||
...emp,
|
||||
official_title: emp.official_title,
|
||||
email: safeDecrypt(emp.email),
|
||||
phone: safeDecrypt(emp.phone),
|
||||
mobile: safeDecrypt(emp.mobile),
|
||||
@ -164,6 +166,7 @@ export function initializeSecureDatabase() {
|
||||
employee_number TEXT UNIQUE NOT NULL,
|
||||
photo TEXT,
|
||||
position TEXT NOT NULL,
|
||||
official_title TEXT,
|
||||
department TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
email_hash TEXT,
|
||||
@ -190,6 +193,10 @@ export function initializeSecureDatabase() {
|
||||
if (!hasPrimaryUnitId) {
|
||||
db.exec(`ALTER TABLE employees ADD COLUMN primary_unit_id TEXT`)
|
||||
}
|
||||
const hasOfficialTitle = cols.some(c => c.name === 'official_title')
|
||||
if (!hasOfficialTitle) {
|
||||
db.exec(`ALTER TABLE employees ADD COLUMN official_title TEXT`)
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ export interface EmployeeInput {
|
||||
employeeNumber?: string | null
|
||||
photo?: string | null
|
||||
position?: string
|
||||
officialTitle?: string | null
|
||||
department: string
|
||||
email: string
|
||||
phone?: string | null
|
||||
@ -76,6 +77,7 @@ export function getAllWithDetails(): Employee[] {
|
||||
employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -136,6 +138,7 @@ function buildEmployeeWithDetails(emp: any): Employee {
|
||||
mobile: emp.mobile,
|
||||
office: emp.office,
|
||||
availability: emp.availability,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
skills: skills.map((s: any) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
@ -166,6 +169,7 @@ export function createEmployee(input: EmployeeInput, actorUserId: string): { id:
|
||||
const now = new Date().toISOString()
|
||||
const employeeId = uuidv4()
|
||||
const position = input.position || 'Teammitglied'
|
||||
const officialTitle = input.officialTitle || null
|
||||
const phone = input.phone || 'Nicht angegeben'
|
||||
const availability = input.availability || 'available'
|
||||
const employeeNumber = input.employeeNumber || `EMP${Date.now()}`
|
||||
@ -186,6 +190,7 @@ export function createEmployee(input: EmployeeInput, actorUserId: string): { id:
|
||||
employee_number: employeeNumber,
|
||||
photo: input.photo || null,
|
||||
position,
|
||||
official_title: officialTitle,
|
||||
department: input.department,
|
||||
email: input.email,
|
||||
phone,
|
||||
@ -249,14 +254,14 @@ export function updateEmployee(id: string, input: EmployeeInput, actorUserId: st
|
||||
|
||||
db.prepare(`
|
||||
UPDATE employees SET
|
||||
first_name = ?, last_name = ?, position = ?, department = ?,
|
||||
first_name = ?, last_name = ?, position = ?, official_title = ?, department = ?,
|
||||
email = ?, email_hash = ?, phone = ?, phone_hash = ?,
|
||||
mobile = ?, office = ?, availability = ?,
|
||||
clearance_level = ?, clearance_valid_until = ?, clearance_issued_date = ?,
|
||||
updated_at = ?, updated_by = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
input.firstName, input.lastName, input.position || 'Teammitglied', input.department,
|
||||
input.firstName, input.lastName, input.position || 'Teammitglied', input.officialTitle || null, input.department,
|
||||
// encryption handled in secure db layer caller; here store encrypted values already in input? Route prepares with FieldEncryption
|
||||
input.email, // already encrypted by route layer
|
||||
null, // email_hash set by route if needed
|
||||
|
||||
@ -34,7 +34,7 @@ function mapProficiencyToLevel(proficiency: string): 'basic' | 'fluent' | 'nativ
|
||||
router.get('/', authenticate, requirePermission('employees:read'), async (req: AuthRequest, res, next) => {
|
||||
try {
|
||||
const employees = db.prepare(`
|
||||
SELECT id, first_name, last_name, employee_number, photo, position,
|
||||
SELECT id, first_name, last_name, employee_number, photo, position, official_title,
|
||||
department, email, phone, mobile, office, availability,
|
||||
clearance_level, clearance_valid_until, clearance_issued_date,
|
||||
created_at, updated_at, created_by, updated_by
|
||||
@ -70,6 +70,7 @@ router.get('/', authenticate, requirePermission('employees:read'), async (req: A
|
||||
employeeNumber: emp.employee_number,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -116,7 +117,7 @@ router.get('/:id', authenticate, requirePermission('employees:read'), async (req
|
||||
const { id } = req.params
|
||||
|
||||
const emp = db.prepare(`
|
||||
SELECT id, first_name, last_name, employee_number, photo, position,
|
||||
SELECT id, first_name, last_name, employee_number, photo, position, official_title,
|
||||
department, email, phone, mobile, office, availability,
|
||||
clearance_level, clearance_valid_until, clearance_issued_date,
|
||||
created_at, updated_at, created_by, updated_by
|
||||
@ -158,6 +159,7 @@ router.get('/:id', authenticate, requirePermission('employees:read'), async (req
|
||||
employeeNumber: emp.employee_number,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -202,6 +204,7 @@ router.post('/',
|
||||
[
|
||||
body('firstName').notEmpty().trim(),
|
||||
body('lastName').notEmpty().trim(),
|
||||
body('officialTitle').optional().trim(),
|
||||
body('email').isEmail(),
|
||||
body('department').notEmpty().trim(),
|
||||
body('organizationUnitId').optional({ checkFalsy: true }).isUUID(),
|
||||
@ -221,7 +224,7 @@ router.post('/',
|
||||
const now = new Date().toISOString()
|
||||
|
||||
const {
|
||||
firstName, lastName, employeeNumber, photo, position,
|
||||
firstName, lastName, employeeNumber, photo, position, officialTitle,
|
||||
department, email, phone, mobile, office, availability,
|
||||
clearance, skills, languages, specializations,
|
||||
userRole, createUser, organizationUnitId, organizationRole
|
||||
@ -253,11 +256,11 @@ router.post('/',
|
||||
// Insert employee with default values for missing fields
|
||||
db.prepare(`
|
||||
INSERT INTO employees (
|
||||
id, first_name, last_name, employee_number, photo, position,
|
||||
id, first_name, last_name, employee_number, photo, position, official_title,
|
||||
department, email, phone, mobile, office, availability, primary_unit_id,
|
||||
clearance_level, clearance_valid_until, clearance_issued_date,
|
||||
created_at, updated_at, created_by
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
employeeId,
|
||||
firstName,
|
||||
@ -265,6 +268,7 @@ router.post('/',
|
||||
employeeNumber || null,
|
||||
photo || null,
|
||||
position || 'Teammitglied', // Default position
|
||||
officialTitle || null,
|
||||
resolvedDepartment,
|
||||
email,
|
||||
phone || 'Nicht angegeben', // Default phone
|
||||
@ -430,6 +434,7 @@ router.put('/:id',
|
||||
body('firstName').notEmpty().trim(),
|
||||
body('lastName').notEmpty().trim(),
|
||||
body('position').notEmpty().trim(),
|
||||
body('officialTitle').optional().trim(),
|
||||
body('department').notEmpty().trim(),
|
||||
body('email').isEmail(),
|
||||
body('phone').notEmpty().trim(),
|
||||
@ -449,7 +454,7 @@ router.put('/:id',
|
||||
const now = new Date().toISOString()
|
||||
|
||||
const {
|
||||
firstName, lastName, position, department, email, phone,
|
||||
firstName, lastName, position, officialTitle, department, email, phone,
|
||||
mobile, office, availability, clearance, skills, languages, specializations
|
||||
} = req.body
|
||||
|
||||
@ -465,13 +470,13 @@ router.put('/:id',
|
||||
// Update employee
|
||||
db.prepare(`
|
||||
UPDATE employees SET
|
||||
first_name = ?, last_name = ?, position = ?, department = ?,
|
||||
first_name = ?, last_name = ?, position = ?, official_title = ?, department = ?,
|
||||
email = ?, phone = ?, mobile = ?, office = ?, availability = ?,
|
||||
clearance_level = ?, clearance_valid_until = ?, clearance_issued_date = ?,
|
||||
updated_at = ?, updated_by = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
firstName, lastName, position, department,
|
||||
firstName, lastName, position, officialTitle || null, department,
|
||||
email, phone, mobile || null, office || null, availability,
|
||||
clearance?.level || null, clearance?.validUntil || null, clearance?.issuedDate || null,
|
||||
now, req.user!.id, id
|
||||
@ -508,6 +513,7 @@ router.put('/:id',
|
||||
firstName,
|
||||
lastName,
|
||||
position,
|
||||
officialTitle: officialTitle || null,
|
||||
department,
|
||||
email,
|
||||
phone,
|
||||
|
||||
@ -121,6 +121,7 @@ router.get('/', authenticate, requirePermission('employees:read'), async (req: A
|
||||
employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -203,6 +204,7 @@ router.get('/public', authenticate, async (req: AuthRequest, res, next) => {
|
||||
employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -285,6 +287,7 @@ router.get('/:id', authenticate, requirePermission('employees:read'), async (req
|
||||
employeeNumber: (emp.employee_number && !String(emp.employee_number).startsWith('EMP')) ? emp.employee_number : undefined,
|
||||
photo: emp.photo,
|
||||
position: emp.position,
|
||||
officialTitle: emp.official_title || undefined,
|
||||
department: emp.department,
|
||||
email: emp.email,
|
||||
phone: emp.phone,
|
||||
@ -354,7 +357,7 @@ router.post('/',
|
||||
const now = new Date().toISOString()
|
||||
|
||||
const {
|
||||
firstName, lastName, employeeNumber, photo, position = 'Teammitglied',
|
||||
firstName, lastName, employeeNumber, photo, position = 'Teammitglied', officialTitle,
|
||||
department, email, phone = 'Nicht angegeben', mobile, office, availability = 'available',
|
||||
clearance, skills = [], languages = [], specializations = [], userRole, createUser,
|
||||
primaryUnitId, assignmentRole
|
||||
@ -380,6 +383,7 @@ router.post('/',
|
||||
employee_number: finalEmployeeNumber,
|
||||
photo: photo || null,
|
||||
position,
|
||||
official_title: officialTitle || null,
|
||||
department,
|
||||
email,
|
||||
phone,
|
||||
@ -513,6 +517,7 @@ router.post('/',
|
||||
employeeNumber: finalEmployeeNumber,
|
||||
photo: photo || null,
|
||||
position,
|
||||
officialTitle: officialTitle || null,
|
||||
department,
|
||||
email,
|
||||
phone,
|
||||
@ -591,6 +596,7 @@ router.put('/:id',
|
||||
body('firstName').notEmpty().trim().escape(),
|
||||
body('lastName').notEmpty().trim().escape(),
|
||||
body('position').optional().trim().escape(),
|
||||
body('officialTitle').optional().trim().escape(),
|
||||
body('department').notEmpty().trim().escape(),
|
||||
body('email').isEmail().normalizeEmail(),
|
||||
body('phone').optional().trim(),
|
||||
@ -612,7 +618,7 @@ router.put('/:id',
|
||||
const now = new Date().toISOString()
|
||||
|
||||
const {
|
||||
firstName, lastName, position = 'Teammitglied', department, email, phone = 'Nicht angegeben',
|
||||
firstName, lastName, position = 'Teammitglied', officialTitle, department, email, phone = 'Nicht angegeben',
|
||||
mobile, office, availability = 'available', clearance, skills, languages, specializations,
|
||||
employeeNumber
|
||||
} = req.body
|
||||
@ -629,14 +635,14 @@ router.put('/:id',
|
||||
// Update employee with encrypted fields
|
||||
db.prepare(`
|
||||
UPDATE employees SET
|
||||
first_name = ?, last_name = ?, position = ?, department = ?,
|
||||
first_name = ?, last_name = ?, position = ?, official_title = ?, department = ?,
|
||||
email = ?, email_hash = ?, phone = ?, phone_hash = ?,
|
||||
mobile = ?, office = ?, availability = ?,
|
||||
clearance_level = ?, clearance_valid_until = ?, clearance_issued_date = ?,
|
||||
updated_at = ?, updated_by = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
firstName, lastName, position, department,
|
||||
firstName, lastName, position, officialTitle || null, department,
|
||||
FieldEncryption.encrypt(email),
|
||||
FieldEncryption.hash(email),
|
||||
FieldEncryption.encrypt(phone || ''),
|
||||
@ -702,6 +708,7 @@ router.put('/:id',
|
||||
firstName,
|
||||
lastName,
|
||||
position,
|
||||
officialTitle: officialTitle || null,
|
||||
department,
|
||||
email,
|
||||
phone,
|
||||
|
||||
@ -18,6 +18,7 @@ export async function createEmployeeUC(req: Request, body: any, actorUserId: str
|
||||
employeeNumber: body.employeeNumber,
|
||||
photo: body.photo,
|
||||
position: body.position,
|
||||
officialTitle: body.officialTitle,
|
||||
department: body.department,
|
||||
email: body.email,
|
||||
phone: body.phone,
|
||||
@ -40,6 +41,7 @@ export async function createEmployeeUC(req: Request, body: any, actorUserId: str
|
||||
employeeNumber: body.employeeNumber || null,
|
||||
photo: body.photo || null,
|
||||
position: body.position || 'Teammitglied',
|
||||
officialTitle: body.officialTitle || null,
|
||||
department: body.department,
|
||||
email: body.email,
|
||||
phone: body.phone || 'Nicht angegeben',
|
||||
@ -65,6 +67,7 @@ export async function updateEmployeeUC(req: Request, id: string, body: any, acto
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
position: body.position,
|
||||
officialTitle: body.officialTitle,
|
||||
department: body.department,
|
||||
email: body.email,
|
||||
phone: body.phone,
|
||||
@ -84,6 +87,7 @@ export async function updateEmployeeUC(req: Request, id: string, body: any, acto
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
position: body.position,
|
||||
officialTitle: body.officialTitle,
|
||||
department: body.department,
|
||||
email: body.email,
|
||||
phone: body.phone,
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren