diff --git a/api/admin/handlers/attendance-handlers.php b/api/admin/handlers/attendance-handlers.php index f86f2d6..d33e826 100644 --- a/api/admin/handlers/attendance-handlers.php +++ b/api/admin/handlers/attendance-handlers.php @@ -7,7 +7,11 @@ function handleGetCurrent(PDO $pdo, int $userId): void $today = date('Y-m-d'); $stmt = $pdo->prepare(" - SELECT * FROM attendance + SELECT id, user_id, shift_date, arrival_time, arrival_lat, arrival_lng, + arrival_accuracy, arrival_address, break_start, break_end, + departure_time, departure_lat, departure_lng, departure_accuracy, + departure_address, notes, project_id, leave_type, leave_hours, created_at + FROM attendance WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work') ORDER BY created_at DESC LIMIT 1 "); @@ -17,7 +21,10 @@ function handleGetCurrent(PDO $pdo, int $userId): void $projectLogs = []; $activeProjectId = null; if ($ongoingShift) { - $stmt = $pdo->prepare('SELECT * FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC'); + $stmt = $pdo->prepare( + 'SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes + FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC' + ); $stmt->execute([$ongoingShift['id']]); $projectLogs = $stmt->fetchAll(); foreach ($projectLogs as $log) { @@ -29,7 +36,11 @@ function handleGetCurrent(PDO $pdo, int $userId): void } $stmt = $pdo->prepare(" - SELECT * FROM attendance + SELECT id, user_id, shift_date, arrival_time, arrival_lat, arrival_lng, + arrival_accuracy, arrival_address, break_start, break_end, + departure_time, departure_lat, departure_lng, departure_accuracy, + departure_address, notes, project_id, leave_type, leave_hours, created_at + FROM attendance WHERE user_id = ? AND shift_date = ? AND departure_time IS NOT NULL AND (leave_type IS NULL OR leave_type = 'work') @@ -43,7 +54,8 @@ function handleGetCurrent(PDO $pdo, int $userId): void if (!empty($completedShiftIds)) { $placeholders = implode(',', array_fill(0, count($completedShiftIds), '?')); $stmt = $pdo->prepare( - "SELECT * FROM attendance_project_logs + "SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes + FROM attendance_project_logs WHERE attendance_id IN ($placeholders) ORDER BY started_at ASC" ); @@ -65,7 +77,9 @@ function handleGetCurrent(PDO $pdo, int $userId): void $endDate = date('Y-m-t'); $stmt = $pdo->prepare(' - SELECT * FROM attendance + SELECT id, user_id, shift_date, arrival_time, break_start, break_end, + departure_time, notes, project_id, leave_type, leave_hours + FROM attendance WHERE user_id = ? AND shift_date BETWEEN ? AND ? '); $stmt->execute([$userId, $startDate, $endDate]); @@ -167,7 +181,10 @@ function handleGetHistory(PDO $pdo, int $userId): void $endDate = date('Y-m-t', strtotime($startDate)); $stmt = $pdo->prepare(' - SELECT * FROM attendance + SELECT id, user_id, shift_date, arrival_time, arrival_address, + break_start, break_end, departure_time, departure_address, + notes, project_id, leave_type, leave_hours, created_at + FROM attendance WHERE user_id = ? AND shift_date BETWEEN ? AND ? ORDER BY shift_date DESC '); @@ -245,7 +262,9 @@ function handlePunch(PDO $pdo, int $userId): void $address = !empty($input['address']) ? $input['address'] : null; $stmt = $pdo->prepare(" - SELECT * FROM attendance + SELECT id, user_id, shift_date, arrival_time, break_start, break_end, + departure_time, notes, project_id, leave_type, created_at + FROM attendance WHERE user_id = ? AND departure_time IS NULL AND (leave_type IS NULL OR leave_type = 'work') ORDER BY created_at DESC LIMIT 1 "); @@ -529,7 +548,10 @@ function handleGetProjectLogs(PDO $pdo, int $currentUserId, array $authData): vo } } - $stmt = $pdo->prepare('SELECT * FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC'); + $stmt = $pdo->prepare( + 'SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes + FROM attendance_project_logs WHERE attendance_id = ? ORDER BY started_at ASC' + ); $stmt->execute([$attendanceId]); $logs = $stmt->fetchAll(); @@ -556,7 +578,7 @@ function handleSaveProjectLogs(PDO $pdo): void errorResponse('attendance_id je povinné'); } - $stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?'); + $stmt = $pdo->prepare('SELECT id FROM attendance WHERE id = ?'); $stmt->execute([$attendanceId]); $record = $stmt->fetch(); if (!$record) { diff --git a/api/admin/handlers/bank-accounts-handlers.php b/api/admin/handlers/bank-accounts-handlers.php index c0aa04c..1a9a829 100644 --- a/api/admin/handlers/bank-accounts-handlers.php +++ b/api/admin/handlers/bank-accounts-handlers.php @@ -4,7 +4,11 @@ declare(strict_types=1); function handleGetBankAccountList(PDO $pdo): void { - $stmt = $pdo->query('SELECT * FROM bank_accounts ORDER BY position, id'); + $stmt = $pdo->query( + 'SELECT id, account_name, bank_name, account_number, iban, bic, + currency, is_default, position, created_at, modified_at + FROM bank_accounts ORDER BY position, id' + ); successResponse($stmt->fetchAll()); } @@ -78,7 +82,11 @@ function handleCreateBankAccount(PDO $pdo): void function handleUpdateBankAccount(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM bank_accounts WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, account_name, bank_name, account_number, iban, bic, + currency, is_default, position + FROM bank_accounts WHERE id = ?' + ); $stmt->execute([$id]); $account = $stmt->fetch(); @@ -145,7 +153,7 @@ function handleUpdateBankAccount(PDO $pdo, int $id): void function handleDeleteBankAccount(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM bank_accounts WHERE id = ?'); + $stmt = $pdo->prepare('SELECT id, account_name FROM bank_accounts WHERE id = ?'); $stmt->execute([$id]); $account = $stmt->fetch(); diff --git a/api/admin/handlers/company-settings-handlers.php b/api/admin/handlers/company-settings-handlers.php index d465e11..c38c035 100644 --- a/api/admin/handlers/company-settings-handlers.php +++ b/api/admin/handlers/company-settings-handlers.php @@ -9,7 +9,13 @@ declare(strict_types=1); function getOrCreateSettings(PDO $pdo, bool $includeLogo = false): array { if ($includeLogo) { - $stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1'); + $stmt = $pdo->query(' + SELECT id, company_name, company_id, vat_id, street, city, postal_code, + country, quotation_prefix, default_currency, default_vat_rate, + custom_fields, logo_data, uuid, modified_at, sync_version, + order_type_code, invoice_type_code, is_deleted, require_2fa + FROM company_settings LIMIT 1 + '); } else { $stmt = $pdo->query(' SELECT id, company_name, company_id, vat_id, street, city, postal_code, country, diff --git a/api/admin/handlers/customers-handlers.php b/api/admin/handlers/customers-handlers.php index ed42e37..3970c9d 100644 --- a/api/admin/handlers/customers-handlers.php +++ b/api/admin/handlers/customers-handlers.php @@ -54,7 +54,9 @@ function encodeCustomerCustomFields(array $input, ?string $existingJson): ?strin function handleGetAll(PDO $pdo): void { $stmt = $pdo->query(' - SELECT c.*, COUNT(q.id) as quotation_count + SELECT c.id, c.name, c.street, c.city, c.postal_code, c.country, + c.company_id, c.vat_id, c.custom_fields, c.created_at, + COUNT(q.id) as quotation_count FROM customers c LEFT JOIN quotations q ON q.customer_id = c.id GROUP BY c.id @@ -72,7 +74,11 @@ function handleGetAll(PDO $pdo): void function handleGetOne(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, street, city, postal_code, country, + company_id, vat_id, custom_fields, created_at + FROM customers WHERE id = ?' + ); $stmt->execute([$id]); $customer = $stmt->fetch(); @@ -93,7 +99,9 @@ function handleSearch(PDO $pdo): void } $stmt = $pdo->prepare(' - SELECT * FROM customers + SELECT id, name, street, city, postal_code, country, + company_id, vat_id, custom_fields + FROM customers WHERE name LIKE ? OR company_id LIKE ? OR city LIKE ? ORDER BY name ASC LIMIT 20 @@ -177,7 +185,11 @@ function handleCreateCustomer(PDO $pdo): void function handleUpdateCustomer(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, street, city, postal_code, country, + company_id, vat_id, custom_fields + FROM customers WHERE id = ?' + ); $stmt->execute([$id]); $existing = $stmt->fetch(); @@ -248,7 +260,7 @@ function handleUpdateCustomer(PDO $pdo, int $id): void function handleDeleteCustomer(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?'); + $stmt = $pdo->prepare('SELECT id, name FROM customers WHERE id = ?'); $stmt->execute([$id]); $customer = $stmt->fetch(); diff --git a/api/admin/handlers/invoices-handlers.php b/api/admin/handlers/invoices-handlers.php index d566bc1..44d15dc 100644 --- a/api/admin/handlers/invoices-handlers.php +++ b/api/admin/handlers/invoices-handlers.php @@ -99,9 +99,6 @@ function handleGetStats(PDO $pdo): void $month = max(1, min(12, (int) ($_GET['month'] ?? (int) date('n')))); $year = max(2020, min(2099, (int) ($_GET['year'] ?? (int) date('Y')))); - // Lazy overdue detekce - $pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()"); - $monthStart = sprintf('%04d-%02d-01', $year, $month); $monthEnd = date('Y-m-t', strtotime($monthStart)); @@ -186,9 +183,6 @@ function handleGetList(PDO $pdo): void $p = PaginationHelper::parseParams($sortMap); - // Lazy overdue detekce - $pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()"); - $where = 'WHERE 1=1'; $params = []; @@ -253,13 +247,14 @@ function handleGetList(PDO $pdo): void function handleGetDetail(PDO $pdo, int $id): void { - // Lazy overdue - $pdo->prepare( - "UPDATE invoices SET status = 'overdue' WHERE id = ? AND status = 'issued' AND due_date < CURDATE()" - )->execute([$id]); - $stmt = $pdo->prepare(' - SELECT i.*, c.name as customer_name, o.order_number + SELECT i.id, i.invoice_number, i.order_id, i.customer_id, i.status, + i.currency, i.vat_rate, i.apply_vat, i.payment_method, + i.constant_symbol, i.bank_name, i.bank_swift, i.bank_iban, + i.bank_account, i.issue_date, i.due_date, i.tax_date, + i.paid_date, i.issued_by, i.notes, i.internal_notes, + i.created_at, i.modified_at, + c.name as customer_name, o.order_number FROM invoices i LEFT JOIN customers c ON i.customer_id = c.id LEFT JOIN orders o ON i.order_id = o.id @@ -273,7 +268,10 @@ function handleGetDetail(PDO $pdo, int $id): void } // Polozky - $stmt = $pdo->prepare('SELECT * FROM invoice_items WHERE invoice_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, invoice_id, description, quantity, unit, unit_price, vat_rate, position + FROM invoice_items WHERE invoice_id = ? ORDER BY position' + ); $stmt->execute([$id]); $invoice['items'] = $stmt->fetchAll(); @@ -317,7 +315,11 @@ function handleGetOrderData(PDO $pdo, int $id): void } // Polozky objednavky - $stmt = $pdo->prepare('SELECT * FROM order_items WHERE order_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, order_id, description, item_description, quantity, unit, + unit_price, is_included_in_total, position + FROM order_items WHERE order_id = ? ORDER BY position' + ); $stmt->execute([$id]); $order['items'] = $stmt->fetchAll(); @@ -506,7 +508,14 @@ function handleCreateInvoice(PDO $pdo, array $authData): void function handleUpdateInvoice(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, invoice_number, order_id, customer_id, status, currency, + vat_rate, apply_vat, payment_method, constant_symbol, + bank_name, bank_swift, bank_iban, bank_account, + issue_date, due_date, tax_date, paid_date, + issued_by, notes, internal_notes + FROM invoices WHERE id = ?' + ); $stmt->execute([$id]); $invoice = $stmt->fetch(); @@ -657,7 +666,9 @@ function handleUpdateInvoice(PDO $pdo, int $id): void function handleDeleteInvoice(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, invoice_number, customer_id FROM invoices WHERE id = ?' + ); $stmt->execute([$id]); $invoice = $stmt->fetch(); diff --git a/api/admin/handlers/leave-requests-handlers.php b/api/admin/handlers/leave-requests-handlers.php index d11d582..d0836b8 100644 --- a/api/admin/handlers/leave-requests-handlers.php +++ b/api/admin/handlers/leave-requests-handlers.php @@ -31,7 +31,10 @@ function getLeaveBalanceForRequest(PDO $pdo, int $userId, ?int $year = null): ar { $year = $year ?: (int)date('Y'); - $stmt = $pdo->prepare('SELECT * FROM leave_balances WHERE user_id = ? AND year = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, year, vacation_total, vacation_used, sick_used + FROM leave_balances WHERE user_id = ? AND year = ?' + ); $stmt->execute([$userId, $year]); $balance = $stmt->fetch(); @@ -77,7 +80,9 @@ function getPendingVacationHours(PDO $pdo, int $userId, int $year): float function handleGetMyRequests(PDO $pdo, int $userId): void { $stmt = $pdo->prepare(" - SELECT lr.*, + SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to, + lr.total_hours, lr.total_days, lr.notes, lr.status, + lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at, CONCAT(u.first_name, ' ', u.last_name) as reviewer_name FROM leave_requests lr LEFT JOIN users u ON lr.reviewer_id = u.id @@ -96,7 +101,9 @@ function handleGetMyRequests(PDO $pdo, int $userId): void function handleGetPending(PDO $pdo): void { $stmt = $pdo->prepare(" - SELECT lr.*, + SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to, + lr.total_hours, lr.total_days, lr.notes, lr.status, + lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at, CONCAT(u.first_name, ' ', u.last_name) as employee_name, CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name FROM leave_requests lr @@ -138,7 +145,9 @@ function handleGetAll(PDO $pdo): void $whereClause = $where ? 'WHERE ' . implode(' AND ', $where) : ''; $stmt = $pdo->prepare(" - SELECT lr.*, + SELECT lr.id, lr.user_id, lr.leave_type, lr.date_from, lr.date_to, + lr.total_hours, lr.total_days, lr.notes, lr.status, + lr.reviewer_id, lr.reviewer_note, lr.reviewed_at, lr.created_at, CONCAT(u.first_name, ' ', u.last_name) as employee_name, CONCAT(rv.first_name, ' ', rv.last_name) as reviewer_name FROM leave_requests lr @@ -270,7 +279,11 @@ function handleCancelRequest(PDO $pdo, int $userId): void errorResponse('ID žádosti je povinné'); } - $stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ? AND user_id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, leave_type, date_from, date_to, total_hours, + total_days, notes, status + FROM leave_requests WHERE id = ? AND user_id = ?' + ); $stmt->execute([$requestId, $userId]); $request = $stmt->fetch(); @@ -310,7 +323,11 @@ function handleApproveRequest(PDO $pdo, int $reviewerId, array $authData): void errorResponse('ID žádosti je povinné'); } - $stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, leave_type, date_from, date_to, total_hours, + total_days, status + FROM leave_requests WHERE id = ?' + ); $stmt->execute([$requestId]); $request = $stmt->fetch(); @@ -427,7 +444,9 @@ function handleRejectRequest(PDO $pdo, int $reviewerId, array $authData): void errorResponse('Důvod zamítnutí je povinný'); } - $stmt = $pdo->prepare('SELECT * FROM leave_requests WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, status FROM leave_requests WHERE id = ?' + ); $stmt->execute([$requestId]); $request = $stmt->fetch(); diff --git a/api/admin/handlers/offers-handlers.php b/api/admin/handlers/offers-handlers.php index 473b0d2..ba5c327 100644 --- a/api/admin/handlers/offers-handlers.php +++ b/api/admin/handlers/offers-handlers.php @@ -54,7 +54,11 @@ function handleGetList(PDO $pdo): void function handleGetDetail(PDO $pdo, int $id): void { $stmt = $pdo->prepare(' - SELECT q.*, c.name as customer_name + SELECT q.id, q.quotation_number, q.project_code, q.customer_id, + q.created_at, q.valid_until, q.currency, q.language, + q.vat_rate, q.apply_vat, q.exchange_rate, q.order_id, + q.status, q.scope_title, q.scope_description, + c.name as customer_name FROM quotations q LEFT JOIN customers c ON q.customer_id = c.id WHERE q.id = ? @@ -68,7 +72,9 @@ function handleGetDetail(PDO $pdo, int $id): void // Get items $stmt = $pdo->prepare(' - SELECT * FROM quotation_items + SELECT id, quotation_id, position, description, item_description, + quantity, unit, unit_price, is_included_in_total + FROM quotation_items WHERE quotation_id = ? ORDER BY position '); @@ -77,7 +83,8 @@ function handleGetDetail(PDO $pdo, int $id): void // Get scope sections $stmt = $pdo->prepare(' - SELECT * FROM scope_sections + SELECT id, quotation_id, position, title, title_cz, content + FROM scope_sections WHERE quotation_id = ? ORDER BY position '); @@ -264,7 +271,12 @@ function handleCreateOffer(PDO $pdo): void function handleUpdateOffer(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_number, project_code, customer_id, created_at, + valid_until, currency, language, vat_rate, apply_vat, + exchange_rate, order_id, status, scope_title, scope_description + FROM quotations WHERE id = ?' + ); $stmt->execute([$id]); $existing = $stmt->fetch(); @@ -349,7 +361,12 @@ function handleUpdateOffer(PDO $pdo, int $id): void function handleDuplicate(PDO $pdo, int $sourceId): void { - $stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_number, project_code, customer_id, currency, + language, vat_rate, apply_vat, exchange_rate, + scope_title, scope_description + FROM quotations WHERE id = ?' + ); $stmt->execute([$sourceId]); $source = $stmt->fetch(); @@ -357,11 +374,18 @@ function handleDuplicate(PDO $pdo, int $sourceId): void errorResponse('Zdrojová nabídka nebyla nalezena', 404); } - $stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT description, item_description, quantity, unit, unit_price, + is_included_in_total, position + FROM quotation_items WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$sourceId]); $sourceItems = $stmt->fetchAll(); - $stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT title, title_cz, content, position + FROM scope_sections WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$sourceId]); $sourceSections = $stmt->fetchAll(); diff --git a/api/admin/handlers/offers-templates-handlers.php b/api/admin/handlers/offers-templates-handlers.php index d97fec4..b41e6ca 100644 --- a/api/admin/handlers/offers-templates-handlers.php +++ b/api/admin/handlers/offers-templates-handlers.php @@ -4,7 +4,10 @@ declare(strict_types=1); function handleGetItemTemplates(PDO $pdo): void { - $stmt = $pdo->query('SELECT * FROM item_templates ORDER BY category, name'); + $stmt = $pdo->query( + 'SELECT id, name, description, default_price, category + FROM item_templates ORDER BY category, name' + ); successResponse(['templates' => $stmt->fetchAll()]); } @@ -100,13 +103,17 @@ function handleDeleteItemTemplate(PDO $pdo, int $id): void function handleGetScopeTemplates(PDO $pdo): void { - $stmt = $pdo->query('SELECT * FROM scope_templates ORDER BY name'); + $stmt = $pdo->query( + 'SELECT id, name, title, description FROM scope_templates ORDER BY name' + ); successResponse(['templates' => $stmt->fetchAll()]); } function handleGetScopeDetail(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM scope_templates WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, title, description FROM scope_templates WHERE id = ?' + ); $stmt->execute([$id]); $template = $stmt->fetch(); @@ -114,7 +121,10 @@ function handleGetScopeDetail(PDO $pdo, int $id): void errorResponse('Šablona nebyla nalezena', 404); } - $stmt = $pdo->prepare('SELECT * FROM scope_template_sections WHERE scope_template_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, scope_template_id, position, title, title_cz, content + FROM scope_template_sections WHERE scope_template_id = ? ORDER BY position' + ); $stmt->execute([$id]); $template['sections'] = $stmt->fetchAll(); diff --git a/api/admin/handlers/orders-handlers.php b/api/admin/handlers/orders-handlers.php index 345ccf3..bc483c3 100644 --- a/api/admin/handlers/orders-handlers.php +++ b/api/admin/handlers/orders-handlers.php @@ -96,12 +96,19 @@ function handleGetDetail(PDO $pdo, int $id): void } // Get items - $stmt = $pdo->prepare('SELECT * FROM order_items WHERE order_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, order_id, description, item_description, quantity, unit, + unit_price, is_included_in_total, position + FROM order_items WHERE order_id = ? ORDER BY position' + ); $stmt->execute([$id]); $order['items'] = $stmt->fetchAll(); // Get sections - $stmt = $pdo->prepare('SELECT * FROM order_sections WHERE order_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, order_id, title, title_cz, content, position + FROM order_sections WHERE order_id = ? ORDER BY position' + ); $stmt->execute([$id]); $order['sections'] = $stmt->fetchAll(); @@ -202,7 +209,12 @@ function handleCreateOrder(PDO $pdo): void } // Verify quotation exists and has no order yet - $stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_number, project_code, customer_id, currency, + language, vat_rate, apply_vat, exchange_rate, order_id, + scope_title, scope_description + FROM quotations WHERE id = ?' + ); $stmt->execute([$quotationId]); $quotation = $stmt->fetch(); @@ -215,11 +227,18 @@ function handleCreateOrder(PDO $pdo): void } // Get quotation items and sections - $stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT description, item_description, quantity, unit, + unit_price, is_included_in_total, position + FROM quotation_items WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$quotationId]); $quotationItems = $stmt->fetchAll(); - $stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT title, title_cz, content, position + FROM scope_sections WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$quotationId]); $quotationSections = $stmt->fetchAll(); @@ -354,7 +373,9 @@ function handleCreateOrder(PDO $pdo): void function handleUpdateOrder(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, order_number, status, notes FROM orders WHERE id = ?' + ); $stmt->execute([$id]); $order = $stmt->fetch(); @@ -461,7 +482,9 @@ function handleUpdateOrder(PDO $pdo, int $id): void function handleDeleteOrder(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM orders WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, order_number, quotation_id FROM orders WHERE id = ?' + ); $stmt->execute([$id]); $order = $stmt->fetch(); diff --git a/api/admin/handlers/projects-handlers.php b/api/admin/handlers/projects-handlers.php index e1dd964..4d986ec 100644 --- a/api/admin/handlers/projects-handlers.php +++ b/api/admin/handlers/projects-handlers.php @@ -114,7 +114,9 @@ function handleCreateProject(PDO $pdo): void function handleDeleteProject(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM projects WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, project_number, name, order_id, status FROM projects WHERE id = ?' + ); $stmt->execute([$id]); $project = $stmt->fetch(); @@ -207,7 +209,10 @@ function handleGetList(PDO $pdo): void function handleGetDetail(PDO $pdo, int $id): void { $stmt = $pdo->prepare(' - SELECT p.*, + SELECT p.id, p.project_number, p.name, p.customer_id, + p.quotation_id, p.order_id, p.status, + p.start_date, p.end_date, p.notes, + p.created_at, p.modified_at, c.name as customer_name, o.order_number, o.status as order_status, q.quotation_number @@ -229,7 +234,10 @@ function handleGetDetail(PDO $pdo, int $id): void function handleUpdateProject(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM projects WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, project_number, name, status, start_date, end_date, notes + FROM projects WHERE id = ?' + ); $stmt->execute([$id]); $project = $stmt->fetch(); diff --git a/api/admin/handlers/received-invoices-handlers.php b/api/admin/handlers/received-invoices-handlers.php index 0c36d0c..c142d7d 100644 --- a/api/admin/handlers/received-invoices-handlers.php +++ b/api/admin/handlers/received-invoices-handlers.php @@ -358,7 +358,12 @@ function handleBulkUpload(PDO $pdo, array $authData): void function handleUpdateReceivedInvoice(PDO $pdo, int $id): void { - $stmt = $pdo->prepare('SELECT * FROM received_invoices WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, supplier_name, invoice_number, description, + amount, currency, vat_rate, vat_amount, + issue_date, due_date, paid_date, status, notes + FROM received_invoices WHERE id = ?' + ); $stmt->execute([$id]); $invoice = $stmt->fetch(); diff --git a/api/admin/handlers/roles-handlers.php b/api/admin/handlers/roles-handlers.php index 4597c69..b9b8188 100644 --- a/api/admin/handlers/roles-handlers.php +++ b/api/admin/handlers/roles-handlers.php @@ -9,7 +9,8 @@ function handleGetRole(PDO $pdo): void { // Get all roles with user count (LEFT JOIN instead of correlated subquery) $stmt = $pdo->query(' - SELECT r.*, COUNT(u.id) as user_count + SELECT r.id, r.name, r.display_name, r.description, r.created_at, + COUNT(u.id) as user_count FROM roles r LEFT JOIN users u ON u.role_id = r.id GROUP BY r.id @@ -133,7 +134,9 @@ function handleCreateRole(PDO $pdo): void function handleUpdateRole(PDO $pdo, int $roleId): void { // Get existing role - $stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, display_name, description FROM roles WHERE id = ?' + ); $stmt->execute([$roleId]); $role = $stmt->fetch(); @@ -205,7 +208,9 @@ function handleUpdateRole(PDO $pdo, int $roleId): void */ function handleDeleteRole(PDO $pdo, int $roleId): void { - $stmt = $pdo->prepare('SELECT * FROM roles WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, display_name, description FROM roles WHERE id = ?' + ); $stmt->execute([$roleId]); $role = $stmt->fetch(); diff --git a/api/admin/handlers/totp-handlers.php b/api/admin/handlers/totp-handlers.php index b6dfc6c..3189ad4 100644 --- a/api/admin/handlers/totp-handlers.php +++ b/api/admin/handlers/totp-handlers.php @@ -181,7 +181,9 @@ function handleVerify(PDO $pdo, TwoFactorAuth $tfa): void $userId = $tokenData['user_id']; $stmt = $pdo->prepare(' - SELECT u.*, r.name as role_name, r.display_name as role_display_name + SELECT u.id, u.username, u.email, u.first_name, u.last_name, + u.role_id, u.is_active, u.totp_secret, u.totp_enabled, + r.name as role_name, r.display_name as role_display_name FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.id = ? AND u.totp_enabled = 1 @@ -230,7 +232,9 @@ function handleBackupVerify(PDO $pdo): void $userId = $tokenData['user_id']; $stmt = $pdo->prepare(' - SELECT u.*, r.name as role_name, r.display_name as role_display_name + SELECT u.id, u.username, u.email, u.first_name, u.last_name, + u.role_id, u.is_active, u.totp_enabled, u.totp_backup_codes, + r.name as role_name, r.display_name as role_display_name FROM users u LEFT JOIN roles r ON u.role_id = r.id WHERE u.id = ? AND u.totp_enabled = 1 @@ -355,7 +359,8 @@ function verifyLoginToken(PDO $pdo, string $token): ?array $hashedToken = hash('sha256', $token); $stmt = $pdo->prepare(' - SELECT * FROM totp_login_tokens + SELECT id, user_id, token_hash, expires_at, created_at + FROM totp_login_tokens WHERE token_hash = ? AND expires_at > NOW() '); $stmt->execute([$hashedToken]); diff --git a/api/admin/handlers/trips-handlers.php b/api/admin/handlers/trips-handlers.php index bb512cc..c9671fb 100644 --- a/api/admin/handlers/trips-handlers.php +++ b/api/admin/handlers/trips-handlers.php @@ -37,7 +37,10 @@ function handleGetCurrent(PDO $pdo, int $userId): void $endDate = date('Y-m-t', strtotime($startDate)); $sql = " - SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model, + SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km, + t.end_km, t.distance, t.route_from, t.route_to, + t.is_business, t.notes, t.created_at, + v.spz, v.name as vehicle_name, v.brand, v.model, CONCAT(u.first_name, ' ', u.last_name) as driver_name FROM trips t JOIN vehicles v ON t.vehicle_id = v.id @@ -101,7 +104,10 @@ function handleGetHistory(PDO $pdo, int $userId): void $endDate = date('Y-m-t', strtotime($startDate)); $sql = " - SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model, + SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km, + t.end_km, t.distance, t.route_from, t.route_to, + t.is_business, t.notes, t.created_at, + v.spz, v.name as vehicle_name, v.brand, v.model, CONCAT(u.first_name, ' ', u.last_name) as driver_name FROM trips t JOIN vehicles v ON t.vehicle_id = v.id @@ -173,7 +179,10 @@ function handleGetAdmin(PDO $pdo): void } $sql = " - SELECT t.*, v.spz, v.name as vehicle_name, + SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km, + t.end_km, t.distance, t.route_from, t.route_to, + t.is_business, t.notes, t.created_at, + v.spz, v.name as vehicle_name, CONCAT(u.first_name, ' ', u.last_name) as driver_name FROM trips t JOIN vehicles v ON t.vehicle_id = v.id @@ -239,7 +248,10 @@ function handleGetAdmin(PDO $pdo): void function handleGetVehicles(PDO $pdo): void { $stmt = $pdo->query(' - SELECT v.*, COUNT(t.id) as trip_count, + SELECT v.id, v.spz, v.name, v.brand, v.model, + v.initial_km, v.actual_km, v.is_active, + v.created_at, v.updated_at, + COUNT(t.id) as trip_count, COALESCE(MAX(t.end_km), v.initial_km) as current_km FROM vehicles v LEFT JOIN trips t ON t.vehicle_id = v.id @@ -415,7 +427,11 @@ function handleVehicle(PDO $pdo): void */ function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void { - $stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, vehicle_id, user_id, trip_date, start_km, end_km, + route_from, route_to, is_business, notes + FROM trips WHERE id = ?' + ); $stmt->execute([$id]); $trip = $stmt->fetch(); @@ -467,7 +483,11 @@ function handleUpdateTrip(PDO $pdo, int $id, int $userId, array $authData): void */ function handleDeleteTrip(PDO $pdo, int $id, int $userId, array $authData): void { - $stmt = $pdo->prepare('SELECT * FROM trips WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, vehicle_id, user_id, trip_date, start_km, end_km, + route_from, route_to, is_business, notes + FROM trips WHERE id = ?' + ); $stmt->execute([$id]); $trip = $stmt->fetch(); @@ -497,7 +517,9 @@ function handleDeleteVehicle(PDO $pdo, int $id): void errorResponse('ID je povinné'); } - $stmt = $pdo->prepare('SELECT * FROM vehicles WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, spz, name, brand, model, is_active FROM vehicles WHERE id = ?' + ); $stmt->execute([$id]); $vehicle = $stmt->fetch(); @@ -573,7 +595,10 @@ function handleGetPrint(PDO $pdo): void } $sql = " - SELECT t.*, v.spz, v.name as vehicle_name, v.brand, v.model, + SELECT t.id, t.vehicle_id, t.user_id, t.trip_date, t.start_km, + t.end_km, t.distance, t.route_from, t.route_to, + t.is_business, t.notes, t.created_at, + v.spz, v.name as vehicle_name, v.brand, v.model, CONCAT(u.first_name, ' ', u.last_name) as driver_name FROM trips t JOIN vehicles v ON t.vehicle_id = v.id diff --git a/api/admin/handlers/users-handlers.php b/api/admin/handlers/users-handlers.php index e3c8f85..a9b1104 100644 --- a/api/admin/handlers/users-handlers.php +++ b/api/admin/handlers/users-handlers.php @@ -142,7 +142,11 @@ function handleCreateUser(PDO $pdo, array $authData): void function handleUpdateUser(PDO $pdo, int $userId, int $currentUserId, array $authData): void { // Get existing user - $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); + $stmt = $pdo->prepare(' + SELECT id, username, email, first_name, last_name, role_id, is_active, + last_login, created_at + FROM users WHERE id = ? + '); $stmt->execute([$userId]); $existingUser = $stmt->fetch(); diff --git a/api/admin/invoices-pdf.php b/api/admin/invoices-pdf.php index 7fdb56a..0ee8c5f 100644 --- a/api/admin/invoices-pdf.php +++ b/api/admin/invoices-pdf.php @@ -43,7 +43,14 @@ $lang = in_array($_GET['lang'] ?? '', ['cs', 'en']) ? $_GET['lang'] : 'cs'; try { $pdo = db(); - $stmt = $pdo->prepare('SELECT * FROM invoices WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, invoice_number, order_id, customer_id, status, currency, + vat_rate, apply_vat, payment_method, constant_symbol, + bank_name, bank_swift, bank_iban, bank_account, + issue_date, due_date, tax_date, paid_date, + issued_by, notes + FROM invoices WHERE id = ?' + ); $stmt->execute([$id]); $invoice = $stmt->fetch(); if (!$invoice) { @@ -52,20 +59,32 @@ try { } // Polozky - $stmt = $pdo->prepare('SELECT * FROM invoice_items WHERE invoice_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, invoice_id, description, quantity, unit, unit_price, vat_rate, position + FROM invoice_items WHERE invoice_id = ? ORDER BY position' + ); $stmt->execute([$id]); $items = $stmt->fetchAll(); // Zakaznik $customer = null; if ($invoice['customer_id']) { - $stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, street, city, postal_code, country, + company_id, vat_id, custom_fields + FROM customers WHERE id = ?' + ); $stmt->execute([$invoice['customer_id']]); $customer = $stmt->fetch(); } // Firemni udaje - $stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1'); + $stmt = $pdo->query( + 'SELECT id, company_name, company_id, vat_id, street, city, + postal_code, country, custom_fields, logo_data, + default_currency, default_vat_rate + FROM company_settings LIMIT 1' + ); $settings = $stmt->fetch(); // Logo diff --git a/api/admin/invoices.php b/api/admin/invoices.php index 73c7f18..e2d9abe 100644 --- a/api/admin/invoices.php +++ b/api/admin/invoices.php @@ -37,6 +37,11 @@ $id = isset($_GET['id']) ? (int) $_GET['id'] : null; try { $pdo = db(); + // Overdue detekce - jednou pred dispatchem (misto v kazdem handleru) + if ($method === 'GET') { + $pdo->exec("UPDATE invoices SET status = 'overdue' WHERE status = 'issued' AND due_date < CURDATE()"); + } + switch ($method) { case 'GET': requirePermission($authData, 'invoices.view'); diff --git a/api/admin/offers-pdf.php b/api/admin/offers-pdf.php index 38c16a4..9698276 100644 --- a/api/admin/offers-pdf.php +++ b/api/admin/offers-pdf.php @@ -38,7 +38,12 @@ if (!$id) { try { $pdo = db(); - $stmt = $pdo->prepare('SELECT * FROM quotations WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_number, project_code, customer_id, created_at, + valid_until, currency, language, vat_rate, apply_vat, + exchange_rate, scope_title, scope_description + FROM quotations WHERE id = ?' + ); $stmt->execute([$id]); $quotation = $stmt->fetch(); if (!$quotation) { @@ -48,20 +53,36 @@ try { $customer = null; if ($quotation['customer_id']) { - $stmt = $pdo->prepare('SELECT * FROM customers WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, name, street, city, postal_code, country, + company_id, vat_id, custom_fields + FROM customers WHERE id = ?' + ); $stmt->execute([$quotation['customer_id']]); $customer = $stmt->fetch(); } - $stmt = $pdo->prepare('SELECT * FROM quotation_items WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_id, position, description, item_description, + quantity, unit, unit_price, is_included_in_total + FROM quotation_items WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$id]); $items = $stmt->fetchAll(); - $stmt = $pdo->prepare('SELECT * FROM scope_sections WHERE quotation_id = ? ORDER BY position'); + $stmt = $pdo->prepare( + 'SELECT id, quotation_id, position, title, title_cz, content + FROM scope_sections WHERE quotation_id = ? ORDER BY position' + ); $stmt->execute([$id]); $sections = $stmt->fetchAll(); - $stmt = $pdo->query('SELECT * FROM company_settings LIMIT 1'); + $stmt = $pdo->query( + 'SELECT id, company_name, company_id, vat_id, street, city, + postal_code, country, custom_fields, logo_data, + quotation_prefix, default_currency, default_vat_rate + FROM company_settings LIMIT 1' + ); $settings = $stmt->fetch(); $logoBase64 = ''; diff --git a/api/admin/profile.php b/api/admin/profile.php index 732a55e..91ceaa2 100644 --- a/api/admin/profile.php +++ b/api/admin/profile.php @@ -35,7 +35,11 @@ try { $userId = $authData['user_id']; // Get existing user - $stmt = $pdo->prepare('SELECT * FROM users WHERE id = ?'); + $stmt = $pdo->prepare(' + SELECT id, username, email, first_name, last_name, role_id, is_active, + last_login, created_at + FROM users WHERE id = ? + '); $stmt->execute([$userId]); $existingUser = $stmt->fetch(); diff --git a/api/includes/AttendanceAdmin.php b/api/includes/AttendanceAdmin.php index 5948a23..4427450 100644 --- a/api/includes/AttendanceAdmin.php +++ b/api/includes/AttendanceAdmin.php @@ -17,7 +17,10 @@ function handleGetAdmin(PDO $pdo): void $endDate = date('Y-m-t', strtotime($startDate)); $sql = " - SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name + SELECT a.id, a.user_id, a.shift_date, a.arrival_time, a.arrival_address, + a.break_start, a.break_end, a.departure_time, a.departure_address, + a.notes, a.project_id, a.leave_type, a.leave_hours, a.created_at, + CONCAT(u.first_name, ' ', u.last_name) as user_name FROM attendance a JOIN users u ON a.user_id = u.id WHERE a.shift_date BETWEEN ? AND ? @@ -112,7 +115,11 @@ function handleGetWorkFund(PDO $pdo): void $startDate = sprintf('%04d-01-01', $year); $endDate = sprintf('%04d-%02d-%02d', $year, $maxMonth, cal_days_in_month(CAL_GREGORIAN, $maxMonth, $year)); - $stmt = $pdo->prepare('SELECT * FROM attendance WHERE shift_date BETWEEN ? AND ? ORDER BY shift_date'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, shift_date, arrival_time, break_start, break_end, + departure_time, notes, project_id, leave_type, leave_hours + FROM attendance WHERE shift_date BETWEEN ? AND ? ORDER BY shift_date' + ); $stmt->execute([$startDate, $endDate]); $allRecords = $stmt->fetchAll(); @@ -206,7 +213,13 @@ function handleGetWorkFund(PDO $pdo): void function handleGetLocation(PDO $pdo, int $recordId): void { $stmt = $pdo->prepare(" - SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name + SELECT a.id, a.user_id, a.shift_date, a.arrival_time, + a.arrival_lat, a.arrival_lng, a.arrival_accuracy, a.arrival_address, + a.break_start, a.break_end, a.departure_time, + a.departure_lat, a.departure_lng, a.departure_accuracy, + a.departure_address, a.notes, a.project_id, + a.leave_type, a.leave_hours, a.created_at, + CONCAT(u.first_name, ' ', u.last_name) as user_name FROM attendance a JOIN users u ON a.user_id = u.id WHERE a.id = ? @@ -467,7 +480,11 @@ function handleUpdateBalance(PDO $pdo): void function handleUpdateAttendance(PDO $pdo, int $recordId): void { - $stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, shift_date, arrival_time, break_start, break_end, + departure_time, notes, project_id, leave_type, leave_hours + FROM attendance WHERE id = ?' + ); $stmt->execute([$recordId]); $record = $stmt->fetch(); @@ -593,7 +610,10 @@ function handleUpdateAttendance(PDO $pdo, int $recordId): void function handleDeleteAttendance(PDO $pdo, int $recordId): void { - $stmt = $pdo->prepare('SELECT * FROM attendance WHERE id = ?'); + $stmt = $pdo->prepare( + 'SELECT id, user_id, shift_date, leave_type, leave_hours + FROM attendance WHERE id = ?' + ); $stmt->execute([$recordId]); $record = $stmt->fetch(); @@ -920,7 +940,10 @@ function handleGetPrint(PDO $pdo): void $users = $stmt->fetchAll(); $sql = " - SELECT a.*, CONCAT(u.first_name, ' ', u.last_name) as user_name + SELECT a.id, a.user_id, a.shift_date, a.arrival_time, a.arrival_address, + a.break_start, a.break_end, a.departure_time, a.departure_address, + a.notes, a.project_id, a.leave_type, a.leave_hours, a.created_at, + CONCAT(u.first_name, ' ', u.last_name) as user_name FROM attendance a JOIN users u ON a.user_id = u.id WHERE a.shift_date BETWEEN ? AND ? diff --git a/api/includes/AttendanceHelpers.php b/api/includes/AttendanceHelpers.php index 3bcf6ca..524b98f 100644 --- a/api/includes/AttendanceHelpers.php +++ b/api/includes/AttendanceHelpers.php @@ -217,7 +217,9 @@ function enrichRecordsWithProjectLogs(PDO $pdo, array &$records): void if (!empty($recordIds)) { $placeholders = implode(',', array_fill(0, count($recordIds), '?')); $stmt = $pdo->prepare( - "SELECT * FROM attendance_project_logs WHERE attendance_id IN ($placeholders) ORDER BY started_at ASC" + "SELECT id, attendance_id, project_id, started_at, ended_at, hours, minutes + FROM attendance_project_logs + WHERE attendance_id IN ($placeholders) ORDER BY started_at ASC" ); $stmt->execute($recordIds); foreach ($stmt->fetchAll() as $log) { diff --git a/api/includes/AuditLog.php b/api/includes/AuditLog.php index c9b707d..5c955b4 100644 --- a/api/includes/AuditLog.php +++ b/api/includes/AuditLog.php @@ -460,7 +460,9 @@ class AuditLog // Get logs $sql = " - SELECT * + SELECT id, user_id, username, user_ip, action, + entity_type, entity_id, description, + old_values, new_values, created_at FROM audit_logs $whereClause ORDER BY created_at DESC @@ -503,7 +505,9 @@ class AuditLog $pdo = db(); $stmt = $pdo->prepare(' - SELECT * + SELECT id, user_id, username, user_ip, action, + entity_type, entity_id, description, + old_values, new_values, created_at FROM audit_logs WHERE user_id = ? ORDER BY created_at DESC @@ -531,7 +535,9 @@ class AuditLog $pdo = db(); $stmt = $pdo->prepare(' - SELECT * + SELECT id, user_id, username, user_ip, action, + entity_type, entity_id, description, + old_values, new_values, created_at FROM audit_logs WHERE entity_type = ? AND entity_id = ? ORDER BY created_at DESC diff --git a/api/includes/JWTAuth.php b/api/includes/JWTAuth.php index 790818b..c5f6d77 100644 --- a/api/includes/JWTAuth.php +++ b/api/includes/JWTAuth.php @@ -245,8 +245,11 @@ class JWTAuth // First check if token exists (regardless of expiry) $stmt = $pdo->prepare(' - SELECT rt.*, u.id as user_id, u.username, u.email, u.first_name, u.last_name, - u.is_active, r.name as role_name, r.display_name as role_display_name + SELECT rt.id, rt.user_id, rt.token_hash, rt.expires_at, + rt.replaced_at, rt.remember_me, + u.id as user_id, u.username, u.email, + u.first_name, u.last_name, u.is_active, + r.name as role_name, r.display_name as role_display_name FROM refresh_tokens rt JOIN users u ON rt.user_id = u.id LEFT JOIN roles r ON u.role_id = r.id diff --git a/api/includes/PaginationHelper.php b/api/includes/PaginationHelper.php index 90d4519..34fc886 100644 --- a/api/includes/PaginationHelper.php +++ b/api/includes/PaginationHelper.php @@ -14,6 +14,7 @@ class PaginationHelper /** * Nacte pagination parametry z GET requestu. * + * @param array $sortMap * @return array{page: int, per_page: int, sort: string, order: string, search: string} */ public static function parseParams(array $sortMap, string $defaultSort = 'created_at'): array @@ -43,9 +44,10 @@ class PaginationHelper * @param PDO $pdo * @param string $countSql - COUNT(*) dotaz * @param string $dataSql - SELECT dotaz (bez LIMIT/OFFSET) - * @param array $params - parametry pro prepared statement + * @param array $params - parametry pro prepared statement * @param array{page: int, per_page: int, sort: string, order: string} $pagination - * @return array{items: array, pagination: array} + * @return array{items: array>, + * pagination: array{total: int, page: int, per_page: int, total_pages: int}} */ public static function paginate( PDO $pdo, diff --git a/api/includes/Validator.php b/api/includes/Validator.php new file mode 100644 index 0000000..bc9cc09 --- /dev/null +++ b/api/includes/Validator.php @@ -0,0 +1,139 @@ +required('name')->string('name', 1, 255); + * $v->required('email')->email('email'); + * $v->int('amount', 0, 1000000); + * $v->in('status', ['active', 'inactive']); + * if ($v->fails()) errorResponse($v->firstError()); + */ + +declare(strict_types=1); + +class Validator +{ + /** @var array */ + private array $data; + + /** @var array */ + private array $errors = []; + + /** @param array $data */ + public function __construct(array $data) + { + $this->data = $data; + } + + public function required(string $field, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + $this->errors[$field] = ($label ?: $field) . ' je povinné pole'; + } + return $this; + } + + public function string(string $field, int $min = 0, int $max = 0, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + return $this; + } + if (!is_string($value)) { + $this->errors[$field] = ($label ?: $field) . ' musí být text'; + return $this; + } + $len = mb_strlen($value); + if ($min > 0 && $len < $min) { + $this->errors[$field] = ($label ?: $field) . " musí mít alespoň {$min} znaků"; + } elseif ($max > 0 && $len > $max) { + $this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max} znaků"; + } + return $this; + } + + public function int(string $field, ?int $min = null, ?int $max = null, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + return $this; + } + if (!is_numeric($value)) { + $this->errors[$field] = ($label ?: $field) . ' musí být číslo'; + return $this; + } + $intVal = (int) $value; + if ($min !== null && $intVal < $min) { + $this->errors[$field] = ($label ?: $field) . " musí být alespoň {$min}"; + } elseif ($max !== null && $intVal > $max) { + $this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max}"; + } + return $this; + } + + public function email(string $field, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + return $this; + } + if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_EMAIL)) { + $this->errors[$field] = ($label ?: $field) . ' musí být platný e-mail'; + } + return $this; + } + + /** + * @param list $allowed + */ + public function in(string $field, array $allowed, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + return $this; + } + if (!in_array($value, $allowed, true)) { + $this->errors[$field] = ($label ?: $field) . ' má neplatnou hodnotu'; + } + return $this; + } + + public function numeric(string $field, ?float $min = null, ?float $max = null, string $label = ''): self + { + $value = $this->data[$field] ?? null; + if ($value === null || $value === '') { + return $this; + } + if (!is_numeric($value)) { + $this->errors[$field] = ($label ?: $field) . ' musí být číslo'; + return $this; + } + $numVal = (float) $value; + if ($min !== null && $numVal < $min) { + $this->errors[$field] = ($label ?: $field) . " musí být alespoň {$min}"; + } elseif ($max !== null && $numVal > $max) { + $this->errors[$field] = ($label ?: $field) . " nesmí překročit {$max}"; + } + return $this; + } + + public function fails(): bool + { + return count($this->errors) > 0; + } + + public function firstError(): string + { + return reset($this->errors) ?: ''; + } + + /** @return array */ + public function errors(): array + { + return $this->errors; + } +}