dodanie csrf, oauth 2, dockerfile
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.git
|
||||
.gitignore
|
||||
node_modules
|
||||
vendor
|
||||
docker-compose.override.yml
|
||||
source/uploads
|
||||
mysql_data
|
||||
@@ -0,0 +1,15 @@
|
||||
APP_NAME=Zeszyt 2.0
|
||||
DB_PREFIX=xyz_
|
||||
|
||||
MYSQL_DATABASE=zeszyt
|
||||
MYSQL_USER=zeszyt
|
||||
MYSQL_PASSWORD=zeszyt
|
||||
MYSQL_ROOT_PASSWORD=root
|
||||
|
||||
MICROSOFT_OAUTH_ENABLED=false
|
||||
MICROSOFT_OAUTH_TENANT=common
|
||||
MICROSOFT_OAUTH_CLIENT_ID=
|
||||
MICROSOFT_OAUTH_CLIENT_SECRET=
|
||||
MICROSOFT_OAUTH_REDIRECT_URI=http://localhost:8080/oauth_callback.php
|
||||
MICROSOFT_OAUTH_ALLOWED_TENANT=
|
||||
MICROSOFT_OAUTH_AUTO_PROVISION=false
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
FROM php:8.2-apache
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libzip-dev \
|
||||
libpng-dev \
|
||||
libjpeg62-turbo-dev \
|
||||
libfreetype6-dev \
|
||||
libonig-dev \
|
||||
unzip \
|
||||
curl \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j"$(nproc)" pdo_mysql mysqli mbstring gd zip \
|
||||
&& a2enmod rewrite headers \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /var/www/html
|
||||
|
||||
COPY source/ /var/www/html/
|
||||
|
||||
RUN mkdir -p /var/www/html/uploads \
|
||||
&& chown -R www-data:www-data /var/www/html
|
||||
|
||||
EXPOSE 80
|
||||
+10
-2
@@ -79,8 +79,14 @@ CREATE TABLE `xyz_settings` (
|
||||
CREATE TABLE `xyz_users` (
|
||||
`id` int NOT NULL,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`email` varchar(255) DEFAULT NULL,
|
||||
`display_name` varchar(255) DEFAULT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`role` enum('admin','user') DEFAULT 'user'
|
||||
`role` enum('admin','user') DEFAULT 'user',
|
||||
`oauth_provider` varchar(50) DEFAULT NULL,
|
||||
`oauth_subject` varchar(191) DEFAULT NULL,
|
||||
`oauth_tenant_id` varchar(64) DEFAULT NULL,
|
||||
`last_login_at` datetime DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
|
||||
-- --------------------------------------------------------
|
||||
@@ -106,7 +112,9 @@ ALTER TABLE `xyz_settings`
|
||||
|
||||
ALTER TABLE `xyz_users`
|
||||
ADD PRIMARY KEY (`id`),
|
||||
ADD UNIQUE KEY `username` (`username`);
|
||||
ADD UNIQUE KEY `username` (`username`),
|
||||
ADD UNIQUE KEY `uniq_users_email` (`email`),
|
||||
ADD KEY `idx_users_oauth_identity` (`oauth_provider`,`oauth_subject`,`oauth_tenant_id`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT dla zrzuconych tabel
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: zeszyt_app
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "8080:80"
|
||||
environment:
|
||||
APP_NAME: "${APP_NAME:-Zeszyt 2.0}"
|
||||
DB_HOST: db
|
||||
DB_NAME: "${MYSQL_DATABASE:-zeszyt}"
|
||||
DB_USER: "${MYSQL_USER:-zeszyt}"
|
||||
DB_PASS: "${MYSQL_PASSWORD:-zeszyt}"
|
||||
DB_PREFIX: "${DB_PREFIX:-xyz_}"
|
||||
MICROSOFT_OAUTH_ENABLED: "${MICROSOFT_OAUTH_ENABLED:-false}"
|
||||
MICROSOFT_OAUTH_TENANT: "${MICROSOFT_OAUTH_TENANT:-common}"
|
||||
MICROSOFT_OAUTH_CLIENT_ID: "${MICROSOFT_OAUTH_CLIENT_ID:-}"
|
||||
MICROSOFT_OAUTH_CLIENT_SECRET: "${MICROSOFT_OAUTH_CLIENT_SECRET:-}"
|
||||
MICROSOFT_OAUTH_REDIRECT_URI: "${MICROSOFT_OAUTH_REDIRECT_URI:-http://localhost:8080/oauth_callback.php}"
|
||||
MICROSOFT_OAUTH_ALLOWED_TENANT: "${MICROSOFT_OAUTH_ALLOWED_TENANT:-}"
|
||||
MICROSOFT_OAUTH_AUTO_PROVISION: "${MICROSOFT_OAUTH_AUTO_PROVISION:-false}"
|
||||
volumes:
|
||||
- ./source:/var/www/html
|
||||
- uploads_data:/var/www/html/uploads
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
image: mysql:8.0
|
||||
container_name: zeszyt_db
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
environment:
|
||||
MYSQL_DATABASE: "${MYSQL_DATABASE:-zeszyt}"
|
||||
MYSQL_USER: "${MYSQL_USER:-zeszyt}"
|
||||
MYSQL_PASSWORD: "${MYSQL_PASSWORD:-zeszyt}"
|
||||
MYSQL_ROOT_PASSWORD: "${MYSQL_ROOT_PASSWORD:-root}"
|
||||
ports:
|
||||
- "3307:3306"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./db/zeszyt.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u${MYSQL_USER:-zeszyt}", "-p${MYSQL_PASSWORD:-zeszyt}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
uploads_data:
|
||||
+30
-27
@@ -5,18 +5,20 @@ checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$product_name = trim($_POST['product_name']);
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
$purchase_place = trim($_POST['purchase_place']);
|
||||
$price = (float)str_replace(',', '.', $_POST['price_per_unit']);
|
||||
$delivery_date = $_POST['delivery_date'];
|
||||
$notes = trim($_POST['notes']);
|
||||
$recipient = trim($_POST['recipient']);
|
||||
$delivery_address = trim($_POST['delivery_address']);
|
||||
$company = trim($_POST['company'] ?? ''); // NOWE POLE
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
requireCsrfToken();
|
||||
|
||||
if (!empty($product_name) && $quantity > 0) {
|
||||
$product_name = trim($_POST['product_name'] ?? '');
|
||||
$quantity = (int)($_POST['quantity'] ?? 0);
|
||||
$purchase_place = trim($_POST['purchase_place'] ?? '');
|
||||
$price = (float)str_replace(',', '.', $_POST['price_per_unit'] ?? '0');
|
||||
$delivery_date = $_POST['delivery_date'] ?? '';
|
||||
$notes = trim($_POST['notes'] ?? '');
|
||||
$recipient = trim($_POST['recipient'] ?? '');
|
||||
$delivery_address = trim($_POST['delivery_address'] ?? '');
|
||||
$company = trim($_POST['company'] ?? '');
|
||||
|
||||
if ($product_name !== '' && $quantity > 0) {
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
@@ -30,17 +32,17 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
|
||||
$hist_sql = "INSERT INTO " . DB_PREFIX . "order_history (order_id, user_id, action) VALUES (?, ?, ?)";
|
||||
$hist_stmt = $pdo->prepare($hist_sql);
|
||||
$hist_stmt->execute([$order_id, $_SESSION['user_id'], 'Utworzono nowe zamówienie.']);
|
||||
$hist_stmt->execute([$order_id, $_SESSION['user_id'], 'Utworzono nowe zamowienie.']);
|
||||
|
||||
$pdo->commit();
|
||||
|
||||
$message = "<div class='alert alert-success'>Zamówienie dodane pomyślnie!</div>";
|
||||
$message = "<div class='alert alert-success'>Zamowienie dodane pomyslnie.</div>";
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd: " . $e->getMessage() . "</div>";
|
||||
error_log($e->getMessage());
|
||||
$message = "<div class='alert alert-danger'>Nie udalo sie zapisac zamowienia.</div>";
|
||||
}
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Wypełnij nazwę produktu i ilość.</div>";
|
||||
$message = "<div class='alert alert-warning'>Wypelnij nazwe produktu i ilosc.</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -49,7 +51,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Dodaj zamówienie - <?php echo APP_NAME; ?></title>
|
||||
<title>Dodaj zamowienie - <?php echo e(APP_NAME); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
</head>
|
||||
@@ -57,18 +59,19 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 600px;">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-plus-circle"></i> Nowe zamówienie</h5>
|
||||
<h5 class="mb-0"><i class="bi bi-plus-circle"></i> Nowe zamowienie</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
|
||||
<div class="mb-3 p-2 bg-success bg-opacity-10 border border-success rounded">
|
||||
<label class="form-label small fw-bold text-success"><i class="bi bi-building"></i> Firma kupująca</label>
|
||||
<label class="form-label small fw-bold text-success"><i class="bi bi-building"></i> Firma kupujaca</label>
|
||||
<select name="company" class="form-select border-success">
|
||||
<option value="">Wybierz firmę...</option>
|
||||
<option value="Przedsiębiorstwo">Przedsiębiorstwo</option>
|
||||
<option value="Spółka">Spółka</option>
|
||||
<option value="">Wybierz firme...</option>
|
||||
<option value="Przedsiebiorstwo">Przedsiebiorstwo</option>
|
||||
<option value="Spolka">Spolka</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -78,14 +81,14 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small fw-bold">Ilość *</label>
|
||||
<label class="form-label small fw-bold">Ilosc *</label>
|
||||
<input type="number" name="quantity" class="form-control" value="1" min="1" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label small fw-bold">Cena za sztukę</label>
|
||||
<label class="form-label small fw-bold">Cena za sztuke</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="price_per_unit" class="form-control" placeholder="0.00">
|
||||
<span class="input-group-text">zł</span>
|
||||
<span class="input-group-text">zl</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,8 +118,8 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót do listy</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Zapisz zamówienie</button>
|
||||
<a href="index.php" class="btn btn-secondary">Powrot do listy</a>
|
||||
<button type="submit" class="btn btn-primary"><i class="bi bi-check-lg"></i> Zapisz zamowienie</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
+152
-148
@@ -3,134 +3,120 @@ require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
|
||||
checkAuth();
|
||||
checkAdmin(); // Tylko admin tu wejdzie
|
||||
checkAdmin();
|
||||
|
||||
$message = '';
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 0. INICJALIZACJA DOMYŚLNYCH USTAWIEŃ FIRM (jeśli nie istnieją)
|
||||
// ---------------------------------------------------------
|
||||
$default_settings = [
|
||||
'company_1_name' => 'Moje Przedsiębiorstwo IT',
|
||||
'company_1_details' => 'ul. Główna 1, 00-000 Warszawa | NIP: 0987654321',
|
||||
'company_2_name' => 'Spółka Celowa Sp. z o.o.',
|
||||
'company_2_details' => 'ul. Przykładowa 10, 00-000 Warszawa | NIP: 1234567890 | KRS: 0000123456'
|
||||
'company_1_name' => 'Moje Przedsiebiorstwo IT',
|
||||
'company_1_details' => 'ul. Glowna 1, 00-000 Warszawa | NIP: 0987654321',
|
||||
'company_2_name' => 'Spolka Celowa Sp. z o.o.',
|
||||
'company_2_details' => 'ul. Przykladowa 10, 00-000 Warszawa | NIP: 1234567890 | KRS: 0000123456'
|
||||
];
|
||||
|
||||
foreach ($default_settings as $key => $val) {
|
||||
// INSERT IGNORE dodaje wpis tylko wtedy, gdy taki klucz jeszcze nie istnieje w tabeli
|
||||
$stmt = $pdo->prepare("INSERT IGNORE INTO " . DB_PREFIX . "settings (setting_key, setting_value) VALUES (?, ?)");
|
||||
$stmt->execute([$key, $val]);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1. WGRYWANIE LOGO
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['logo'])) {
|
||||
if ($_FILES['logo']['error'] === 0) {
|
||||
$upload_dir = 'uploads/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
requireCsrfToken();
|
||||
|
||||
$file_ext = strtolower(pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION));
|
||||
if(in_array($file_ext, ['jpg', 'jpeg', 'png', 'gif', 'svg'])) {
|
||||
$new_name = 'logo_' . time() . '.' . $file_ext;
|
||||
$dest_path = $upload_dir . $new_name;
|
||||
if (isset($_FILES['logo'])) {
|
||||
if ($_FILES['logo']['error'] === 0) {
|
||||
$upload_dir = 'uploads/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0755, true);
|
||||
}
|
||||
|
||||
if (move_uploaded_file($_FILES['logo']['tmp_name'], $dest_path)) {
|
||||
$stmt = $pdo->prepare("REPLACE INTO " . DB_PREFIX . "settings (setting_key, setting_value) VALUES ('logo_path', ?)");
|
||||
$stmt->execute([$dest_path]);
|
||||
$message = "<div class='alert alert-success'>Pomyślnie zaktualizowano logo!</div>";
|
||||
$tmpPath = $_FILES['logo']['tmp_name'];
|
||||
$mime = mime_content_type($tmpPath);
|
||||
$allowedMimes = [
|
||||
'image/jpeg' => 'jpg',
|
||||
'image/png' => 'png',
|
||||
'image/gif' => 'gif',
|
||||
];
|
||||
|
||||
if (isset($allowedMimes[$mime]) && @getimagesize($tmpPath) !== false) {
|
||||
$new_name = 'logo_' . bin2hex(random_bytes(8)) . '.' . $allowedMimes[$mime];
|
||||
$dest_path = $upload_dir . $new_name;
|
||||
|
||||
if (move_uploaded_file($tmpPath, $dest_path)) {
|
||||
$stmt = $pdo->prepare("REPLACE INTO " . DB_PREFIX . "settings (setting_key, setting_value) VALUES ('logo_path', ?)");
|
||||
$stmt->execute([$dest_path]);
|
||||
$message = "<div class='alert alert-success'>Pomyslnie zaktualizowano logo.</div>";
|
||||
} else {
|
||||
$message = "<div class='alert alert-danger'>Nie udalo sie zapisac pliku.</div>";
|
||||
}
|
||||
} else {
|
||||
$message = "<div class='alert alert-danger'>Błąd: Nie udało się zapisać pliku. Sprawdź uprawnienia folderu 'uploads'.</div>";
|
||||
}
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Błąd: Dozwolone są tylko pliki graficzne (JPG, PNG, GIF, SVG).</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 1B. ZAPISYWANIE DANYCH FIRM
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'update_company_settings') {
|
||||
$settings_to_update = ['company_1_name', 'company_1_details', 'company_2_name', 'company_2_details'];
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
$update_stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "settings SET setting_value = ? WHERE setting_key = ?");
|
||||
|
||||
foreach ($settings_to_update as $key) {
|
||||
if (isset($_POST[$key])) {
|
||||
$update_stmt->execute([trim($_POST[$key]), $key]);
|
||||
$message = "<div class='alert alert-warning'>Dozwolone sa tylko prawidlowe pliki JPG, PNG i GIF.</div>";
|
||||
}
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Ustawienia firmowe zostały zapisane!</div>";
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd zapisu: " . $e->getMessage() . "</div>";
|
||||
}
|
||||
}
|
||||
} elseif (isset($_POST['action']) && $_POST['action'] === 'update_company_settings') {
|
||||
$settings_to_update = ['company_1_name', 'company_1_details', 'company_2_name', 'company_2_details'];
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 2. DODAWANIE UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_user'])) {
|
||||
$new_user = trim($_POST['new_username']);
|
||||
$new_pass = $_POST['new_password'];
|
||||
$new_role = $_POST['new_role'];
|
||||
|
||||
if (!empty($new_user) && !empty($new_pass)) {
|
||||
try {
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("INSERT INTO " . DB_PREFIX . "users (username, password, role) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$new_user, $hashed_pass, $new_role]);
|
||||
$message = "<div class='alert alert-success'>Dodano nowego użytkownika: <strong>$new_user</strong></div>";
|
||||
$pdo->beginTransaction();
|
||||
$update_stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "settings SET setting_value = ? WHERE setting_key = ?");
|
||||
|
||||
foreach ($settings_to_update as $key) {
|
||||
if (isset($_POST[$key])) {
|
||||
$update_stmt->execute([trim($_POST[$key]), $key]);
|
||||
}
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Ustawienia firmowe zostaly zapisane.</div>";
|
||||
} catch (PDOException $e) {
|
||||
$message = "<div class='alert alert-danger'>Błąd: Użytkownik o takiej nazwie prawdopodobnie już istnieje.</div>";
|
||||
$pdo->rollBack();
|
||||
error_log($e->getMessage());
|
||||
$message = "<div class='alert alert-danger'>Nie udalo sie zapisac ustawien.</div>";
|
||||
}
|
||||
} elseif (isset($_POST['add_user'])) {
|
||||
$new_user = trim($_POST['new_username'] ?? '');
|
||||
$new_pass = $_POST['new_password'] ?? '';
|
||||
$new_role = $_POST['new_role'] ?? 'user';
|
||||
|
||||
if ($new_user !== '' && $new_pass !== '') {
|
||||
try {
|
||||
$new_email = trim($_POST['new_email'] ?? '');
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("INSERT INTO " . DB_PREFIX . "users (username, email, password, role) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$new_user, $new_email !== '' ? $new_email : null, $hashed_pass, $new_role === 'admin' ? 'admin' : 'user']);
|
||||
$message = "<div class='alert alert-success'>Dodano nowego uzytkownika: <strong>" . e($new_user) . "</strong></div>";
|
||||
} catch (PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
$message = "<div class='alert alert-danger'>Nie udalo sie dodac uzytkownika.</div>";
|
||||
}
|
||||
}
|
||||
} elseif (isset($_POST['reset_password'])) {
|
||||
$user_id = (int)($_POST['user_id'] ?? 0);
|
||||
$new_pass = $_POST['new_password'] ?? '';
|
||||
|
||||
if ($user_id > 0 && $new_pass !== '') {
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "users SET password = ? WHERE id = ?");
|
||||
$stmt->execute([$hashed_pass, $user_id]);
|
||||
$message = "<div class='alert alert-info'>Zmieniono haslo dla wybranego uzytkownika.</div>";
|
||||
}
|
||||
} elseif (isset($_POST['delete_user'])) {
|
||||
$id_to_delete = (int)($_POST['user_id'] ?? 0);
|
||||
if ($id_to_delete !== (int)$_SESSION['user_id']) {
|
||||
$stmt = $pdo->prepare("DELETE FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$stmt->execute([$id_to_delete]);
|
||||
$message = "<div class='alert alert-success'>Uzytkownik zostal pomyslnie usuniety.</div>";
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Nie mozesz usunac wlasnego konta administratora.</div>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 3. RESET HASŁA UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['reset_password'])) {
|
||||
$user_id = (int)$_POST['user_id'];
|
||||
$new_pass = $_POST['new_password'];
|
||||
|
||||
if (!empty($new_pass)) {
|
||||
$hashed_pass = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$stmt = $pdo->prepare("UPDATE " . DB_PREFIX . "users SET password = ? WHERE id = ?");
|
||||
$stmt->execute([$hashed_pass, $user_id]);
|
||||
$message = "<div class='alert alert-info'>Zmieniono hasło dla wybranego użytkownika.</div>";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// 4. USUWANIE UŻYTKOWNIKA
|
||||
// ---------------------------------------------------------
|
||||
if (isset($_GET['delete'])) {
|
||||
$id_to_delete = (int)$_GET['delete'];
|
||||
if ($id_to_delete != $_SESSION['user_id']) {
|
||||
$stmt = $pdo->prepare("DELETE FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$stmt->execute([$id_to_delete]);
|
||||
$message = "<div class='alert alert-success'>Użytkownik został pomyślnie usunięty.</div>";
|
||||
} else {
|
||||
$message = "<div class='alert alert-warning'>Odmowa: Nie możesz usunąć własnego konta administratora!</div>";
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
// POBIERANIE DANYCH DO WIDOKU
|
||||
// ---------------------------------------------------------
|
||||
$users = $pdo->query("SELECT id, username, role FROM " . DB_PREFIX . "users")->fetchAll();
|
||||
$users = $pdo->query("SELECT id, username, email, role, oauth_provider, last_login_at FROM " . DB_PREFIX . "users ORDER BY username ASC")->fetchAll();
|
||||
|
||||
$settings = [];
|
||||
try {
|
||||
$settings = $pdo->query("SELECT setting_key, setting_value FROM " . DB_PREFIX . "settings")->fetchAll(PDO::FETCH_KEY_PAIR);
|
||||
} catch(PDOException $e) {
|
||||
// Zabezpieczenie na wypadek awarii tabeli settings
|
||||
} catch (PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
|
||||
$current_logo = $settings['logo_path'] ?? '';
|
||||
@@ -141,7 +127,7 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Panel Administratora - <?php echo defined('APP_NAME') ? APP_NAME : 'System'; ?></title>
|
||||
<title>Panel administratora - <?php echo e(defined('APP_NAME') ? APP_NAME : 'System'); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
|
||||
<style>
|
||||
@@ -154,20 +140,20 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-4 shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="index.php">
|
||||
<?php if($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo $current_logo; ?>" alt="Logo" class="logo-img me-2">
|
||||
<?php if ($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo e($current_logo); ?>" alt="Logo" class="logo-img me-2">
|
||||
<?php else: ?>
|
||||
<span class="me-2">💻</span>
|
||||
<span class="me-2">IT</span>
|
||||
<?php endif; ?>
|
||||
<strong><?php echo defined('APP_NAME') ? APP_NAME : 'System IT'; ?></strong>
|
||||
<strong><?php echo e(defined('APP_NAME') ? APP_NAME : 'System IT'); ?></strong>
|
||||
</a>
|
||||
|
||||
<div class="navbar-nav ms-auto align-items-center">
|
||||
<button class="btn btn-sm btn-outline-secondary me-3" onclick="toggleDarkMode()">
|
||||
<i class="bi bi-moon-stars" id="themeIcon"></i>
|
||||
</button>
|
||||
<span class="nav-link text-light me-3 small">Admin: <strong><?php echo $_SESSION['username']; ?></strong></span>
|
||||
<a class="btn btn-outline-light btn-sm me-2" href="index.php"><i class="bi bi-arrow-left"></i> Powrót do zamówień</a>
|
||||
<span class="nav-link text-light me-3 small">Admin: <strong><?php echo e($_SESSION['username']); ?></strong></span>
|
||||
<a class="btn btn-outline-light btn-sm me-2" href="index.php"><i class="bi bi-arrow-left"></i> Powrot do zamowien</a>
|
||||
<a class="btn btn-outline-danger btn-sm" href="logout.php">Wyloguj</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,30 +161,30 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
|
||||
<div class="container pb-5">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Panel Zarządzania Systemem</h2>
|
||||
<h2>Panel zarzadzania systemem</h2>
|
||||
</div>
|
||||
|
||||
<?php echo $message; ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 mb-4">
|
||||
|
||||
<div class="card shadow-sm mb-4 border-0">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<i class="bi bi-image"></i> Ustawienia Wizualne
|
||||
<i class="bi bi-image"></i> Ustawienia wizualne
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="text-center mb-3">
|
||||
<?php if($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo $current_logo; ?>" class="img-thumbnail" style="max-height: 80px;">
|
||||
<?php if ($current_logo && file_exists($current_logo)): ?>
|
||||
<img src="<?php echo e($current_logo); ?>" class="img-thumbnail" style="max-height: 80px;" alt="Logo">
|
||||
<?php else: ?>
|
||||
<div class="text-muted small">Brak wgranego logo</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Zmień logotyp (PNG/JPG)</label>
|
||||
<input type="file" name="logo" class="form-control form-control-sm" accept="image/*" required>
|
||||
<label class="form-label small">Zmien logotyp (PNG/JPG/GIF)</label>
|
||||
<input type="file" name="logo" class="form-control form-control-sm" accept=".png,.jpg,.jpeg,.gif" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-dark w-100 btn-sm">Wgraj plik na serwer</button>
|
||||
</form>
|
||||
@@ -207,28 +193,29 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
|
||||
<div class="card shadow-sm border-0 mb-4">
|
||||
<div class="card-header bg-info text-dark fw-bold">
|
||||
<i class="bi bi-buildings"></i> Dane firm (Stopki wydruków)
|
||||
<i class="bi bi-buildings"></i> Dane firm
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
<input type="hidden" name="action" value="update_company_settings">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold text-primary">1. Przedsiębiorstwo (Nazwa)</label>
|
||||
<input type="text" name="company_1_name" class="form-control form-control-sm border-primary" value="<?php echo htmlspecialchars($settings['company_1_name'] ?? ''); ?>" required>
|
||||
<label class="form-label small fw-bold text-primary">1. Przedsiebiorstwo (Nazwa)</label>
|
||||
<input type="text" name="company_1_name" class="form-control form-control-sm border-primary" value="<?php echo e($settings['company_1_name'] ?? ''); ?>" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label small fw-bold text-primary">Przedsiębiorstwo (Adres/NIP)</label>
|
||||
<input type="text" name="company_1_details" class="form-control form-control-sm" value="<?php echo htmlspecialchars($settings['company_1_details'] ?? ''); ?>">
|
||||
<label class="form-label small fw-bold text-primary">Przedsiebiorstwo (Adres/NIP)</label>
|
||||
<input type="text" name="company_1_details" class="form-control form-control-sm" value="<?php echo e($settings['company_1_details'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-3 border-top pt-3">
|
||||
<label class="form-label small fw-bold text-success">2. Spółka (Nazwa)</label>
|
||||
<input type="text" name="company_2_name" class="form-control form-control-sm border-success" value="<?php echo htmlspecialchars($settings['company_2_name'] ?? ''); ?>" required>
|
||||
<label class="form-label small fw-bold text-success">2. Spolka (Nazwa)</label>
|
||||
<input type="text" name="company_2_name" class="form-control form-control-sm border-success" value="<?php echo e($settings['company_2_name'] ?? ''); ?>" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label small fw-bold text-success">Spółka (Adres/NIP/KRS)</label>
|
||||
<input type="text" name="company_2_details" class="form-control form-control-sm" value="<?php echo htmlspecialchars($settings['company_2_details'] ?? ''); ?>">
|
||||
<label class="form-label small fw-bold text-success">Spolka (Adres/NIP/KRS)</label>
|
||||
<input type="text" name="company_2_details" class="form-control form-control-sm" value="<?php echo e($settings['company_2_details'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-info w-100 btn-sm fw-bold text-dark"><i class="bi bi-save"></i> Zapisz stopki firm</button>
|
||||
@@ -242,26 +229,30 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Login użytkownika</label>
|
||||
<label class="form-label small">Login uzytkownika</label>
|
||||
<input type="text" name="new_username" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Hasło początkowe</label>
|
||||
<input type="password" name="new_password" class="form-control" required>
|
||||
<label class="form-label small">Haslo poczatkowe</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="8">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Email do powiazania z Microsoft 365</label>
|
||||
<input type="email" name="new_email" class="form-control" placeholder="np. user@firma.pl">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small">Rola w systemie</label>
|
||||
<select name="new_role" class="form-select">
|
||||
<option value="user">Zwykły pracownik</option>
|
||||
<option value="user">Zwykly pracownik</option>
|
||||
<option value="admin">Administrator</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" name="add_user" class="btn btn-primary w-100"><i class="bi bi-check2-circle"></i> Utwórz konto</button>
|
||||
<button type="submit" name="add_user" class="btn btn-primary w-100"><i class="bi bi-check2-circle"></i> Utworz konto</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-7">
|
||||
@@ -276,49 +267,62 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
<tr>
|
||||
<th class="px-3">ID</th>
|
||||
<th>Login</th>
|
||||
<th>Email</th>
|
||||
<th>Uprawnienia</th>
|
||||
<th class="text-end px-4">Zarządzaj</th>
|
||||
<th>Zrodlo</th>
|
||||
<th class="text-end px-4">Zarzadzaj</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $u): ?>
|
||||
<tr>
|
||||
<td class="px-3 text-muted"><?php echo $u['id']; ?></td>
|
||||
<td><strong><?php echo htmlspecialchars($u['username']); ?></strong></td>
|
||||
<td class="px-3 text-muted"><?php echo (int)$u['id']; ?></td>
|
||||
<td><strong><?php echo e($u['username']); ?></strong></td>
|
||||
<td class="small text-muted"><?php echo e($u['email'] ?? ''); ?></td>
|
||||
<td>
|
||||
<span class="badge <?php echo $u['role'] == 'admin' ? 'bg-danger' : 'bg-primary'; ?>">
|
||||
<?php echo $u['role'] == 'admin' ? 'Administrator' : 'Użytkownik'; ?>
|
||||
<span class="badge <?php echo $u['role'] === 'admin' ? 'bg-danger' : 'bg-primary'; ?>">
|
||||
<?php echo $u['role'] === 'admin' ? 'Administrator' : 'Uzytkownik'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge <?php echo $u['oauth_provider'] === 'microsoft' ? 'bg-success' : 'bg-secondary'; ?>">
|
||||
<?php echo $u['oauth_provider'] === 'microsoft' ? 'Microsoft 365' : 'Lokalne'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-end px-3">
|
||||
<button class="btn btn-sm btn-outline-info me-1" data-bs-toggle="modal" data-bs-target="#resetModal<?php echo $u['id']; ?>">
|
||||
<i class="bi bi-shield-lock"></i> Reset hasła
|
||||
<button class="btn btn-sm btn-outline-info me-1" data-bs-toggle="modal" data-bs-target="#resetModal<?php echo (int)$u['id']; ?>">
|
||||
<i class="bi bi-shield-lock"></i> Reset hasla
|
||||
</button>
|
||||
|
||||
<?php if ($u['id'] != $_SESSION['user_id']): ?>
|
||||
<a href="?delete=<?php echo $u['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Czy na pewno chcesz bezpowrotnie usunąć to konto?')">
|
||||
<i class="bi bi-trash"></i> Usuń
|
||||
</a>
|
||||
<?php if ((int)$u['id'] !== (int)$_SESSION['user_id']): ?>
|
||||
<form method="POST" class="d-inline" onsubmit="return confirm('Czy na pewno chcesz bezpowrotnie usunac to konto?')">
|
||||
<?php echo csrfInput(); ?>
|
||||
<input type="hidden" name="user_id" value="<?php echo (int)$u['id']; ?>">
|
||||
<button type="submit" name="delete_user" class="btn btn-sm btn-outline-danger">
|
||||
<i class="bi bi-trash"></i> Usun
|
||||
</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<button class="btn btn-sm btn-outline-secondary disabled"><i class="bi bi-person-check"></i> To ty</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="modal fade" id="resetModal<?php echo $u['id']; ?>" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal fade" id="resetModal<?php echo (int)$u['id']; ?>" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm modal-dialog-centered">
|
||||
<div class="modal-content text-start">
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="modal-header bg-light">
|
||||
<h6 class="modal-title"><i class="bi bi-key"></i> Nowe hasło: <?php echo $u['username']; ?></h6>
|
||||
<h6 class="modal-title"><i class="bi bi-key"></i> Nowe haslo: <?php echo e($u['username']); ?></h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>">
|
||||
<label class="form-label small">Wpisz nowe hasło:</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="4">
|
||||
<input type="hidden" name="user_id" value="<?php echo (int)$u['id']; ?>">
|
||||
<label class="form-label small">Wpisz nowe haslo:</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="8">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Anuluj</button>
|
||||
<button type="submit" name="reset_password" class="btn btn-info btn-sm text-white">Zapisz hasło</button>
|
||||
<button type="submit" name="reset_password" class="btn btn-info btn-sm text-white">Zapisz haslo</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -349,7 +353,7 @@ $current_logo = $settings['logo_path'] ?? '';
|
||||
localStorage.setItem('theme', newTheme);
|
||||
}
|
||||
|
||||
if(localStorage.getItem('theme') === 'dark') {
|
||||
if (localStorage.getItem('theme') === 'dark') {
|
||||
document.getElementById('mainHtml').setAttribute('data-bs-theme', 'dark');
|
||||
document.getElementById('themeIcon').classList.replace('bi-moon-stars', 'bi-sun');
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ if (!$data || empty($data['action']) || empty($data['id'])) {
|
||||
die(json_encode(['success' => false, 'error' => 'Brak danych']));
|
||||
}
|
||||
|
||||
if (!isValidCsrfToken($data['csrf_token'] ?? null)) {
|
||||
http_response_code(403);
|
||||
die(json_encode(['success' => false, 'error' => 'Nieprawidlowy token bezpieczenstwa']));
|
||||
}
|
||||
|
||||
$id = (int)$data['id'];
|
||||
$action = $data['action'];
|
||||
|
||||
@@ -61,6 +66,7 @@ try {
|
||||
echo json_encode(['success' => false, 'error' => 'Nieznana akcja']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(['success' => false, 'error' => 'Wystapil blad serwera']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -10,6 +10,11 @@ if (!$data || empty(trim($data['product_name']))) {
|
||||
die(json_encode(['success' => false, 'error' => 'Nazwa produktu jest wymagana!']));
|
||||
}
|
||||
|
||||
if (!isValidCsrfToken($data['csrf_token'] ?? null)) {
|
||||
http_response_code(403);
|
||||
die(json_encode(['success' => false, 'error' => 'Nieprawidlowy token bezpieczenstwa']));
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo->beginTransaction();
|
||||
|
||||
@@ -34,6 +39,7 @@ try {
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (PDOException $e) {
|
||||
$pdo->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(['success' => false, 'error' => 'Wystapil blad serwera']);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -10,6 +10,11 @@ if (!$data || !isset($data['id'], $data['field'], $data['value'])) {
|
||||
die(json_encode(['success' => false, 'error' => 'Brak danych']));
|
||||
}
|
||||
|
||||
if (!isValidCsrfToken($data['csrf_token'] ?? null)) {
|
||||
http_response_code(403);
|
||||
die(json_encode(['success' => false, 'error' => 'Nieprawidlowy token bezpieczenstwa']));
|
||||
}
|
||||
|
||||
$id = (int)$data['id'];
|
||||
$field = $data['field'];
|
||||
$value = trim($data['value']);
|
||||
@@ -58,6 +63,7 @@ try {
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
error_log($e->getMessage());
|
||||
echo json_encode(['success' => false, 'error' => 'Wystapil blad serwera']);
|
||||
}
|
||||
?>
|
||||
|
||||
+20
-18
@@ -5,27 +5,28 @@ checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$old_pass = $_POST['old_password'];
|
||||
$new_pass = $_POST['new_password'];
|
||||
$confirm_pass = $_POST['confirm_password'];
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
requireCsrfToken();
|
||||
|
||||
$old_pass = $_POST['old_password'] ?? '';
|
||||
$new_pass = $_POST['new_password'] ?? '';
|
||||
$confirm_pass = $_POST['confirm_password'] ?? '';
|
||||
|
||||
if ($new_pass !== $confirm_pass) {
|
||||
$message = '<div class="alert alert-danger">Nowe hasła nie są identyczne!</div>';
|
||||
$message = '<div class="alert alert-danger">Nowe hasla nie sa identyczne.</div>';
|
||||
} else {
|
||||
// Pobierz aktualne hasło z bazy
|
||||
$stmt = $pdo->prepare("SELECT password FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (password_verify($old_pass, $user['password'])) {
|
||||
// Hasło poprawne - aktualizujemy
|
||||
if ($user && password_verify($old_pass, $user['password'])) {
|
||||
$new_hash = password_hash($new_pass, PASSWORD_BCRYPT);
|
||||
$update = $pdo->prepare("UPDATE " . DB_PREFIX . "users SET password = ? WHERE id = ?");
|
||||
$update->execute([$new_hash, $_SESSION['user_id']]);
|
||||
$message = '<div class="alert alert-success">Hasło zostało zmienione pomyślnie!</div>';
|
||||
session_regenerate_id(true);
|
||||
$message = '<div class="alert alert-success">Haslo zostalo zmienione pomyslnie.</div>';
|
||||
} else {
|
||||
$message = '<div class="alert alert-danger">Obecne hasło jest nieprawidłowe.</div>';
|
||||
$message = '<div class="alert alert-danger">Obecne haslo jest nieprawidlowe.</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,34 +36,35 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Zmiana hasła - <?php echo APP_NAME; ?></title>
|
||||
<title>Zmiana hasla - <?php echo e(APP_NAME); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<div class="card shadow mx-auto" style="max-width: 450px;">
|
||||
<div class="card-header bg-dark text-white">
|
||||
<h5 class="mb-0">Zmiana hasła</h5>
|
||||
<h5 class="mb-0">Zmiana hasla</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Obecne hasło</label>
|
||||
<label class="form-label">Obecne haslo</label>
|
||||
<input type="password" name="old_password" class="form-control" required>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nowe hasło</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="5">
|
||||
<label class="form-label">Nowe haslo</label>
|
||||
<input type="password" name="new_password" class="form-control" required minlength="8">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Powtórz nowe hasło</label>
|
||||
<label class="form-label">Powtorz nowe haslo</label>
|
||||
<input type="password" name="confirm_password" class="form-control" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<button type="submit" class="btn btn-primary">Zmień hasło</button>
|
||||
<a href="index.php" class="btn btn-secondary">Powrot</a>
|
||||
<button type="submit" class="btn btn-primary">Zmien haslo</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,7 @@ if (!$order) {
|
||||
|
||||
// 1. OBSŁUGA ZMIANY STATUSU ARCHIWUM
|
||||
if (isset($_POST['archive_action'])) {
|
||||
requireCsrfToken();
|
||||
$new_archive_status = $order['is_archived'] ? 0 : 1;
|
||||
|
||||
$update_arch = $pdo->prepare("UPDATE " . DB_PREFIX . "orders SET is_archived = ? WHERE id = ?");
|
||||
@@ -33,6 +34,7 @@ if (isset($_POST['archive_action'])) {
|
||||
|
||||
// 2. OBSŁUGA DODAWANIA KOMENTARZA
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_comment'])) {
|
||||
requireCsrfToken();
|
||||
$comment_text = trim($_POST['comment_text'] ?? '');
|
||||
|
||||
if (!empty($comment_text)) {
|
||||
@@ -51,6 +53,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_comment'])) {
|
||||
|
||||
// 3. OBSŁUGA STANDARDOWEJ EDYCJI
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && !isset($_POST['archive_action']) && !isset($_POST['add_comment'])) {
|
||||
requireCsrfToken();
|
||||
$product_name = trim($_POST['product_name'] ?? '');
|
||||
$part_number = trim($_POST['part_number'] ?? '');
|
||||
$quantity = (int)$_POST['quantity'];
|
||||
@@ -170,6 +173,7 @@ $comments = $comm_stmt->fetchAll();
|
||||
<div class="card-body">
|
||||
<?php echo $message; ?>
|
||||
<form method="POST">
|
||||
<?php echo csrfInput(); ?>
|
||||
|
||||
<div class="mb-3 p-2 bg-success bg-opacity-10 border border-success rounded">
|
||||
<label class="form-label small fw-bold text-success"><i class="bi bi-building"></i> Firma kupująca</label>
|
||||
@@ -262,6 +266,7 @@ $comments = $comm_stmt->fetchAll();
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<form method="POST" class="mb-3">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="input-group shadow-sm">
|
||||
<textarea name="comment_text" class="form-control" rows="2" placeholder="Wpisz nowy komentarz..." required></textarea>
|
||||
<button type="submit" name="add_comment" class="btn btn-primary px-3"><i class="bi bi-send"></i></button>
|
||||
|
||||
+18
-8
@@ -3,7 +3,17 @@ require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
function sanitizeCsvCell($value) {
|
||||
$value = (string)$value;
|
||||
if ($value !== '' && preg_match('/^[=\+\-@]/', $value) === 1) {
|
||||
return "'" . $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
requireCsrfToken();
|
||||
$ids = $_POST['order_ids'];
|
||||
|
||||
// Tworzenie znaków zapytania do zapytania SQL (np. ?, ?, ?)
|
||||
@@ -31,16 +41,16 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
foreach ($orders as $o) {
|
||||
fputcsv($output, [
|
||||
$o['id'],
|
||||
$o['product_name'],
|
||||
$o['part_number'],
|
||||
sanitizeCsvCell($o['product_name']),
|
||||
sanitizeCsvCell($o['part_number']),
|
||||
$o['quantity'],
|
||||
$o['purchase_place'],
|
||||
sanitizeCsvCell($o['purchase_place']),
|
||||
number_format($o['price_per_unit'], 2, ',', ''), // Cena z przecinkiem dla Excela
|
||||
$o['delivery_date'],
|
||||
$o['recipient'],
|
||||
$o['delivery_address'],
|
||||
$o['status'],
|
||||
$o['notes']
|
||||
sanitizeCsvCell($o['delivery_date']),
|
||||
sanitizeCsvCell($o['recipient']),
|
||||
sanitizeCsvCell($o['delivery_address']),
|
||||
sanitizeCsvCell($o['status']),
|
||||
sanitizeCsvCell($o['notes'])
|
||||
], ';');
|
||||
}
|
||||
|
||||
|
||||
+22
-21
@@ -6,11 +6,11 @@ checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['csv_file'])) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES['csv_file'])) {
|
||||
requireCsrfToken();
|
||||
$file = $_FILES['csv_file']['tmp_name'];
|
||||
|
||||
if (($handle = fopen($file, "r")) !== FALSE) {
|
||||
// Pomijamy pierwszy wiersz (nagłówki)
|
||||
if (($handle = fopen($file, "r")) !== false) {
|
||||
fgetcsv($handle, 1000, ";");
|
||||
|
||||
try {
|
||||
@@ -21,32 +21,32 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['csv_file'])) {
|
||||
$stmt = $pdo->prepare($sql);
|
||||
|
||||
$count = 0;
|
||||
while (($row = fgetcsv($handle, 1000, ";")) !== FALSE) {
|
||||
// $row[0] to LP - pomijamy zgodnie z wymaganiem
|
||||
|
||||
// Obsługa polskich znaków (jeśli plik jest w Windows-1250)
|
||||
foreach($row as $key => $value) {
|
||||
while (($row = fgetcsv($handle, 1000, ";")) !== false) {
|
||||
foreach ($row as $key => $value) {
|
||||
$row[$key] = mb_convert_encoding($value, "UTF-8", "auto");
|
||||
}
|
||||
|
||||
if (empty($row[1])) continue; // Pomiń jeśli brak nazwy produktu
|
||||
if (empty($row[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt->execute([
|
||||
$row[1], // Produkt
|
||||
(int)$row[2], // Ilość
|
||||
$row[3], // Miejsce zakupu
|
||||
(float)str_replace(',', '.', $row[4]), // Cena (zamiana przecinka na kropkę)
|
||||
$row[5], // Data dostawy
|
||||
$row[6], // Notatki
|
||||
$row[7] ?? 'nowe' // Status
|
||||
$row[1],
|
||||
(int)$row[2],
|
||||
$row[3],
|
||||
(float)str_replace(',', '.', $row[4]),
|
||||
$row[5],
|
||||
$row[6],
|
||||
$row[7] ?? 'nowe'
|
||||
]);
|
||||
$count++;
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Zaimportowano $count zamówień z pliku CSV!</div>";
|
||||
$message = "<div class='alert alert-success'>Zaimportowano $count zamowien z pliku CSV.</div>";
|
||||
} catch (Exception $e) {
|
||||
$pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd: " . $e->getMessage() . "</div>";
|
||||
error_log($e->getMessage());
|
||||
$message = "<div class='alert alert-danger'>Import nie powiodl sie.</div>";
|
||||
}
|
||||
fclose($handle);
|
||||
}
|
||||
@@ -57,7 +57,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['csv_file'])) {
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Import CSV - <?php echo APP_NAME; ?></title>
|
||||
<title>Import CSV - <?php echo e(APP_NAME); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
@@ -70,16 +70,17 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['csv_file'])) {
|
||||
<?php echo $message; ?>
|
||||
|
||||
<div class="alert alert-warning small">
|
||||
<strong>Ważne:</strong> W Excelu wybierz <em>Zapisz jako</em> -> <strong>CSV (rozdzielany średnikami)</strong>.
|
||||
<strong>Wazne:</strong> W Excelu wybierz <em>Zapisz jako</em> -> <strong>CSV (rozdzielany srednikami)</strong>.
|
||||
</div>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Wybierz plik .csv</label>
|
||||
<input type="file" name="csv_file" class="form-control" accept=".csv" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<a href="index.php" class="btn btn-secondary">Powrot</a>
|
||||
<button type="submit" class="btn btn-success">Importuj dane</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
+24
-25
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
require 'vendor/autoload.php'; // Ładowanie biblioteki PhpSpreadsheet
|
||||
require 'vendor/autoload.php';
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
|
||||
@@ -9,15 +9,14 @@ checkAuth();
|
||||
|
||||
$message = '';
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['excel_file'])) {
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && isset($_FILES['excel_file'])) {
|
||||
requireCsrfToken();
|
||||
$file = $_FILES['excel_file']['tmp_name'];
|
||||
|
||||
try {
|
||||
$spreadsheet = IOFactory::load($file);
|
||||
$worksheet = $spreadsheet->getActiveSheet();
|
||||
$rows = $worksheet->toArray();
|
||||
|
||||
// Pomijamy nagłówek (pierwszy wiersz w Excelu)
|
||||
unset($rows[0]);
|
||||
|
||||
$pdo->beginTransaction();
|
||||
@@ -28,30 +27,29 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['excel_file'])) {
|
||||
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
// Zgodnie z wymaganiem: pomijamy 1. kolumnę ($row[0])
|
||||
// Mapowanie kolumn Excela:
|
||||
// $row[1] -> Produkt, $row[2] -> Ilość, $row[3] -> Miejsce,
|
||||
// $row[4] -> Cena, $row[5] -> Data, $row[6] -> Notatki, $row[7] -> Status
|
||||
|
||||
if (empty($row[1])) continue; // Pomiń puste wiersze
|
||||
if (empty($row[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt->execute([
|
||||
$row[1], // Produkt
|
||||
(int)$row[2], // Ilość
|
||||
$row[3], // Miejsce zakupu
|
||||
(float)$row[4], // Cena
|
||||
$row[5], // Data dostawy (format YYYY-MM-DD)
|
||||
$row[6], // Notatki
|
||||
$row[7] ?? 'nowe' // Status
|
||||
$row[1],
|
||||
(int)$row[2],
|
||||
$row[3],
|
||||
(float)$row[4],
|
||||
$row[5],
|
||||
$row[6],
|
||||
$row[7] ?? 'nowe'
|
||||
]);
|
||||
$count++;
|
||||
}
|
||||
$pdo->commit();
|
||||
$message = "<div class='alert alert-success'>Pomyślnie zaimportowano $count zamówień!</div>";
|
||||
|
||||
$message = "<div class='alert alert-success'>Pomyslnie zaimportowano $count zamowien.</div>";
|
||||
} catch (Exception $e) {
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
$message = "<div class='alert alert-danger'>Błąd importu: " . $e->getMessage() . "</div>";
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
error_log($e->getMessage());
|
||||
$message = "<div class='alert alert-danger'>Import nie powiodl sie.</div>";
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -60,7 +58,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['excel_file'])) {
|
||||
<html lang="pl">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Import Zamówień - <?php echo APP_NAME; ?></title>
|
||||
<title>Import zamowien - <?php echo e(APP_NAME); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
@@ -74,17 +72,18 @@ if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_FILES['excel_file'])) {
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>Instrukcja:</strong><br>
|
||||
1. System pomija pierwszą kolumnę (LP).<br>
|
||||
2. Kolejne kolumny to: Produkt, Ilość, Miejsce, Cena, Data (RRRR-MM-DD), Notatki, Status.
|
||||
1. System pomija pierwsza kolumne (LP).<br>
|
||||
2. Kolejne kolumny to: Produkt, Ilosc, Miejsce, Cena, Data (RRRR-MM-DD), Notatki, Status.
|
||||
</div>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Wybierz plik Excel</label>
|
||||
<input type="file" name="excel_file" class="form-control" accept=".xlsx, .xls" required>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="index.php" class="btn btn-secondary">Powrót</a>
|
||||
<a href="index.php" class="btn btn-secondary">Powrot</a>
|
||||
<button type="submit" class="btn btn-success">Rozpocznij import</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,7 +1,41 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
||||
$isHttps = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
session_set_cookie_params([
|
||||
'httponly' => true,
|
||||
'secure' => $isHttps,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
session_start();
|
||||
}
|
||||
|
||||
function e($value) {
|
||||
return htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
function getCsrfToken() {
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
return $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
function csrfInput() {
|
||||
return '<input type="hidden" name="csrf_token" value="' . e(getCsrfToken()) . '">';
|
||||
}
|
||||
|
||||
function isValidCsrfToken($token) {
|
||||
return is_string($token) && hash_equals(getCsrfToken(), $token);
|
||||
}
|
||||
|
||||
function requireCsrfToken($token = null) {
|
||||
if (!isValidCsrfToken($token ?? ($_POST['csrf_token'] ?? null))) {
|
||||
http_response_code(403);
|
||||
exit('Blad bezpieczenstwa: nieprawidlowy token formularza.');
|
||||
}
|
||||
}
|
||||
|
||||
// Funkcja sprawdzająca czy użytkownik jest zalogowany
|
||||
function checkAuth() {
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
@@ -9,10 +43,10 @@ function checkAuth() {
|
||||
}
|
||||
}
|
||||
|
||||
// Funkcja sprawdzająca czy użytkownik jest adminem
|
||||
function checkAdmin() {
|
||||
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
|
||||
die("Błąd: Brak uprawnień administratora.");
|
||||
http_response_code(403);
|
||||
exit('Blad: Brak uprawnien administratora.');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
+23
-10
@@ -1,14 +1,27 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('display_startup_errors', '0');
|
||||
error_reporting(E_ALL);
|
||||
// Dane do połączenia z bazą
|
||||
define('DB_HOST', '');
|
||||
define('DB_NAME', '');
|
||||
define('DB_USER', ''); // Zmień na swojego użytkownika bazy
|
||||
define('DB_PASS', ''); // Zmień na swoje hasło
|
||||
define('DB_PREFIX', '');
|
||||
|
||||
// Ustawienia aplikacji
|
||||
define('APP_NAME', ' Zeszyt 2.0');
|
||||
function envOrDefault($name, $default = '') {
|
||||
$value = getenv($name);
|
||||
return $value !== false ? $value : $default;
|
||||
}
|
||||
|
||||
define('DB_HOST', envOrDefault('DB_HOST', 'db'));
|
||||
define('DB_NAME', envOrDefault('DB_NAME', 'zeszyt'));
|
||||
define('DB_USER', envOrDefault('DB_USER', 'zeszyt'));
|
||||
define('DB_PASS', envOrDefault('DB_PASS', 'zeszyt'));
|
||||
define('DB_PREFIX', envOrDefault('DB_PREFIX', 'xyz_'));
|
||||
|
||||
define('APP_NAME', envOrDefault('APP_NAME', 'Zeszyt 2.0'));
|
||||
|
||||
// Przyklad redirect URI: http://localhost:8080/oauth_callback.php
|
||||
define('MICROSOFT_OAUTH_ENABLED', filter_var(envOrDefault('MICROSOFT_OAUTH_ENABLED', 'false'), FILTER_VALIDATE_BOOLEAN));
|
||||
define('MICROSOFT_OAUTH_TENANT', envOrDefault('MICROSOFT_OAUTH_TENANT', 'common'));
|
||||
define('MICROSOFT_OAUTH_CLIENT_ID', envOrDefault('MICROSOFT_OAUTH_CLIENT_ID', ''));
|
||||
define('MICROSOFT_OAUTH_CLIENT_SECRET', envOrDefault('MICROSOFT_OAUTH_CLIENT_SECRET', ''));
|
||||
define('MICROSOFT_OAUTH_REDIRECT_URI', envOrDefault('MICROSOFT_OAUTH_REDIRECT_URI', ''));
|
||||
define('MICROSOFT_OAUTH_ALLOWED_TENANT', envOrDefault('MICROSOFT_OAUTH_ALLOWED_TENANT', ''));
|
||||
define('MICROSOFT_OAUTH_AUTO_PROVISION', filter_var(envOrDefault('MICROSOFT_OAUTH_AUTO_PROVISION', 'false'), FILTER_VALIDATE_BOOLEAN));
|
||||
?>
|
||||
|
||||
@@ -10,7 +10,63 @@ try {
|
||||
];
|
||||
|
||||
$pdo = new PDO($dsn, DB_USER, DB_PASS, $options);
|
||||
ensureOptionalSchema($pdo);
|
||||
} catch (\PDOException $e) {
|
||||
throw new \PDOException($e->getMessage(), (int)$e->getCode());
|
||||
}
|
||||
|
||||
function ensureOptionalSchema(PDO $pdo) {
|
||||
static $done = false;
|
||||
|
||||
if ($done || DB_PREFIX === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$done = true;
|
||||
$usersTable = DB_PREFIX . "users";
|
||||
|
||||
try {
|
||||
$columns = $pdo->query("SHOW COLUMNS FROM {$usersTable}")->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||
$indexes = $pdo->query("SHOW INDEX FROM {$usersTable}")->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (\PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$indexNames = array_column($indexes, 'Key_name');
|
||||
$statements = [];
|
||||
|
||||
if (!in_array('email', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN email varchar(255) DEFAULT NULL AFTER username";
|
||||
}
|
||||
if (!in_array('display_name', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN display_name varchar(255) DEFAULT NULL AFTER email";
|
||||
}
|
||||
if (!in_array('oauth_provider', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN oauth_provider varchar(50) DEFAULT NULL AFTER role";
|
||||
}
|
||||
if (!in_array('oauth_subject', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN oauth_subject varchar(191) DEFAULT NULL AFTER oauth_provider";
|
||||
}
|
||||
if (!in_array('oauth_tenant_id', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN oauth_tenant_id varchar(64) DEFAULT NULL AFTER oauth_subject";
|
||||
}
|
||||
if (!in_array('last_login_at', $columns, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD COLUMN last_login_at datetime DEFAULT NULL AFTER oauth_tenant_id";
|
||||
}
|
||||
if (!in_array('uniq_users_email', $indexNames, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD UNIQUE KEY uniq_users_email (email)";
|
||||
}
|
||||
if (!in_array('idx_users_oauth_identity', $indexNames, true)) {
|
||||
$statements[] = "ALTER TABLE {$usersTable} ADD KEY idx_users_oauth_identity (oauth_provider, oauth_subject, oauth_tenant_id)";
|
||||
}
|
||||
|
||||
foreach ($statements as $statement) {
|
||||
try {
|
||||
$pdo->exec($statement);
|
||||
} catch (\PDOException $e) {
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/auth.php';
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
function isMicrosoftOAuthConfigured() {
|
||||
return MICROSOFT_OAUTH_ENABLED
|
||||
&& MICROSOFT_OAUTH_CLIENT_ID !== ''
|
||||
&& MICROSOFT_OAUTH_CLIENT_SECRET !== ''
|
||||
&& MICROSOFT_OAUTH_REDIRECT_URI !== '';
|
||||
}
|
||||
|
||||
function getMicrosoftOAuthTenant() {
|
||||
return MICROSOFT_OAUTH_TENANT !== '' ? MICROSOFT_OAUTH_TENANT : 'common';
|
||||
}
|
||||
|
||||
function getMicrosoftOAuthBaseUrl() {
|
||||
return 'https://login.microsoftonline.com/' . rawurlencode(getMicrosoftOAuthTenant()) . '/oauth2/v2.0';
|
||||
}
|
||||
|
||||
function buildMicrosoftAuthorizationUrl() {
|
||||
$state = bin2hex(random_bytes(32));
|
||||
$nonce = bin2hex(random_bytes(32));
|
||||
|
||||
$_SESSION['microsoft_oauth_state'] = $state;
|
||||
$_SESSION['microsoft_oauth_nonce'] = $nonce;
|
||||
|
||||
$params = [
|
||||
'client_id' => MICROSOFT_OAUTH_CLIENT_ID,
|
||||
'response_type' => 'code',
|
||||
'redirect_uri' => MICROSOFT_OAUTH_REDIRECT_URI,
|
||||
'response_mode' => 'query',
|
||||
'scope' => 'openid profile email offline_access',
|
||||
'state' => $state,
|
||||
'nonce' => $nonce,
|
||||
];
|
||||
|
||||
return getMicrosoftOAuthBaseUrl() . '/authorize?' . http_build_query($params);
|
||||
}
|
||||
|
||||
function exchangeMicrosoftCodeForTokens($code) {
|
||||
$response = httpPostForm(
|
||||
getMicrosoftOAuthBaseUrl() . '/token',
|
||||
[
|
||||
'client_id' => MICROSOFT_OAUTH_CLIENT_ID,
|
||||
'client_secret' => MICROSOFT_OAUTH_CLIENT_SECRET,
|
||||
'grant_type' => 'authorization_code',
|
||||
'code' => $code,
|
||||
'redirect_uri' => MICROSOFT_OAUTH_REDIRECT_URI,
|
||||
]
|
||||
);
|
||||
|
||||
if ($response['status'] < 200 || $response['status'] >= 300) {
|
||||
throw new RuntimeException('Microsoft token endpoint returned HTTP ' . $response['status']);
|
||||
}
|
||||
|
||||
$payload = json_decode($response['body'], true);
|
||||
if (!is_array($payload) || empty($payload['id_token'])) {
|
||||
throw new RuntimeException('Brak id_token w odpowiedzi Microsoft');
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
function decodeJwtPayload($jwt) {
|
||||
$parts = explode('.', $jwt);
|
||||
if (count($parts) < 2) {
|
||||
throw new RuntimeException('Nieprawidlowy format JWT');
|
||||
}
|
||||
|
||||
$payload = json_decode(base64UrlDecode($parts[1]), true);
|
||||
if (!is_array($payload)) {
|
||||
throw new RuntimeException('Nie mozna odczytac payload JWT');
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
function base64UrlDecode($data) {
|
||||
$remainder = strlen($data) % 4;
|
||||
if ($remainder > 0) {
|
||||
$data .= str_repeat('=', 4 - $remainder);
|
||||
}
|
||||
|
||||
return base64_decode(strtr($data, '-_', '+/'));
|
||||
}
|
||||
|
||||
function extractMicrosoftIdentity(array $tokenPayload) {
|
||||
$claims = decodeJwtPayload($tokenPayload['id_token']);
|
||||
$expectedNonce = $_SESSION['microsoft_oauth_nonce'] ?? null;
|
||||
|
||||
unset($_SESSION['microsoft_oauth_nonce']);
|
||||
|
||||
if (!$expectedNonce || !hash_equals($expectedNonce, (string)($claims['nonce'] ?? ''))) {
|
||||
throw new RuntimeException('Nieprawidlowy nonce odpowiedzi Microsoft');
|
||||
}
|
||||
|
||||
if ((string)($claims['aud'] ?? '') !== MICROSOFT_OAUTH_CLIENT_ID) {
|
||||
throw new RuntimeException('Token Microsoft ma nieprawidlowe aud');
|
||||
}
|
||||
|
||||
if ((int)($claims['exp'] ?? 0) < time()) {
|
||||
throw new RuntimeException('Token Microsoft wygasl');
|
||||
}
|
||||
|
||||
$tenantId = (string)($claims['tid'] ?? '');
|
||||
$objectId = (string)($claims['oid'] ?? '');
|
||||
if ($tenantId === '' || $objectId === '') {
|
||||
throw new RuntimeException('Brak wymaganych claimow tid/oid');
|
||||
}
|
||||
|
||||
$issuer = (string)($claims['iss'] ?? '');
|
||||
if ($issuer === '' || strpos($issuer, 'https://login.microsoftonline.com/') !== 0) {
|
||||
throw new RuntimeException('Token Microsoft ma nieprawidlowe iss');
|
||||
}
|
||||
|
||||
if (MICROSOFT_OAUTH_ALLOWED_TENANT !== '' && !hash_equals(MICROSOFT_OAUTH_ALLOWED_TENANT, $tenantId)) {
|
||||
throw new RuntimeException('Ten tenant Microsoft nie jest dozwolony');
|
||||
}
|
||||
|
||||
$email = trim((string)($claims['email'] ?? ''));
|
||||
$preferredUsername = trim((string)($claims['preferred_username'] ?? ''));
|
||||
if ($email === '' && filter_var($preferredUsername, FILTER_VALIDATE_EMAIL)) {
|
||||
$email = $preferredUsername;
|
||||
}
|
||||
|
||||
return [
|
||||
'tenant_id' => $tenantId,
|
||||
'subject' => $objectId,
|
||||
'display_name' => trim((string)($claims['name'] ?? '')),
|
||||
'email' => $email,
|
||||
'preferred_username' => $preferredUsername,
|
||||
];
|
||||
}
|
||||
|
||||
function findOrProvisionMicrosoftUser(PDO $pdo, array $identity) {
|
||||
$lookup = $pdo->prepare(
|
||||
"SELECT * FROM " . DB_PREFIX . "users WHERE oauth_provider = 'microsoft' AND oauth_subject = ? AND oauth_tenant_id = ? LIMIT 1"
|
||||
);
|
||||
$lookup->execute([$identity['subject'], $identity['tenant_id']]);
|
||||
$user = $lookup->fetch();
|
||||
if ($user) {
|
||||
return updateMicrosoftUserProfile($pdo, $user, $identity);
|
||||
}
|
||||
|
||||
$candidate = $identity['email'] !== '' ? $identity['email'] : $identity['preferred_username'];
|
||||
if ($candidate !== '') {
|
||||
$link = $pdo->prepare(
|
||||
"SELECT * FROM " . DB_PREFIX . "users WHERE email = ? OR username = ? LIMIT 1"
|
||||
);
|
||||
$link->execute([$candidate, $candidate]);
|
||||
$user = $link->fetch();
|
||||
if ($user) {
|
||||
$stmt = $pdo->prepare(
|
||||
"UPDATE " . DB_PREFIX . "users
|
||||
SET email = COALESCE(email, ?), display_name = ?, oauth_provider = 'microsoft', oauth_subject = ?, oauth_tenant_id = ?, last_login_at = NOW()
|
||||
WHERE id = ?"
|
||||
);
|
||||
$stmt->execute([
|
||||
$identity['email'] !== '' ? $identity['email'] : null,
|
||||
$identity['display_name'] !== '' ? $identity['display_name'] : null,
|
||||
$identity['subject'],
|
||||
$identity['tenant_id'],
|
||||
$user['id'],
|
||||
]);
|
||||
|
||||
$reload = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$reload->execute([$user['id']]);
|
||||
return $reload->fetch();
|
||||
}
|
||||
}
|
||||
|
||||
if (!MICROSOFT_OAUTH_AUTO_PROVISION) {
|
||||
throw new RuntimeException('To konto Microsoft nie jest powiazane z zadnym lokalnym uzytkownikiem');
|
||||
}
|
||||
|
||||
$usernameBase = $candidate !== '' ? $candidate : 'm365_' . substr($identity['subject'], 0, 12);
|
||||
$username = makeUniqueUsername($pdo, $usernameBase);
|
||||
$passwordHash = password_hash(bin2hex(random_bytes(24)), PASSWORD_BCRYPT);
|
||||
|
||||
$insert = $pdo->prepare(
|
||||
"INSERT INTO " . DB_PREFIX . "users
|
||||
(username, email, display_name, password, role, oauth_provider, oauth_subject, oauth_tenant_id, last_login_at)
|
||||
VALUES (?, ?, ?, ?, 'user', 'microsoft', ?, ?, NOW())"
|
||||
);
|
||||
$insert->execute([
|
||||
$username,
|
||||
$identity['email'] !== '' ? $identity['email'] : null,
|
||||
$identity['display_name'] !== '' ? $identity['display_name'] : null,
|
||||
$passwordHash,
|
||||
$identity['subject'],
|
||||
$identity['tenant_id'],
|
||||
]);
|
||||
|
||||
$reload = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$reload->execute([$pdo->lastInsertId()]);
|
||||
return $reload->fetch();
|
||||
}
|
||||
|
||||
function updateMicrosoftUserProfile(PDO $pdo, array $user, array $identity) {
|
||||
$stmt = $pdo->prepare(
|
||||
"UPDATE " . DB_PREFIX . "users
|
||||
SET email = COALESCE(?, email), display_name = COALESCE(?, display_name), last_login_at = NOW()
|
||||
WHERE id = ?"
|
||||
);
|
||||
$stmt->execute([
|
||||
$identity['email'] !== '' ? $identity['email'] : null,
|
||||
$identity['display_name'] !== '' ? $identity['display_name'] : null,
|
||||
$user['id'],
|
||||
]);
|
||||
|
||||
$reload = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "users WHERE id = ?");
|
||||
$reload->execute([$user['id']]);
|
||||
return $reload->fetch();
|
||||
}
|
||||
|
||||
function makeUniqueUsername(PDO $pdo, $base) {
|
||||
$base = preg_replace('/[^a-zA-Z0-9._@-]/', '_', $base);
|
||||
$base = trim($base, '_');
|
||||
if ($base === '') {
|
||||
$base = 'user';
|
||||
}
|
||||
|
||||
$candidate = $base;
|
||||
$i = 1;
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM " . DB_PREFIX . "users WHERE username = ?");
|
||||
|
||||
while (true) {
|
||||
$stmt->execute([$candidate]);
|
||||
if ((int)$stmt->fetchColumn() === 0) {
|
||||
return $candidate;
|
||||
}
|
||||
|
||||
$i++;
|
||||
$candidate = $base . '_' . $i;
|
||||
}
|
||||
}
|
||||
|
||||
function loginUserIntoSession(array $user) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
}
|
||||
|
||||
function httpPostForm($url, array $fields) {
|
||||
$body = http_build_query($fields);
|
||||
|
||||
if (function_exists('curl_init')) {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => $body,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
|
||||
CURLOPT_TIMEOUT => 15,
|
||||
]);
|
||||
$responseBody = curl_exec($ch);
|
||||
if ($responseBody === false) {
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
throw new RuntimeException('Blad cURL: ' . $error);
|
||||
}
|
||||
$status = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return ['status' => $status, 'body' => $responseBody];
|
||||
}
|
||||
|
||||
$context = stream_context_create([
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
|
||||
'content' => $body,
|
||||
'timeout' => 15,
|
||||
'ignore_errors' => true,
|
||||
],
|
||||
]);
|
||||
$responseBody = file_get_contents($url, false, $context);
|
||||
if ($responseBody === false) {
|
||||
throw new RuntimeException('Nie mozna polaczyc sie z Microsoft');
|
||||
}
|
||||
|
||||
$status = 0;
|
||||
foreach ($http_response_header ?? [] as $header) {
|
||||
if (preg_match('#HTTP/\S+\s+(\d+)#', $header, $matches)) {
|
||||
$status = (int)$matches[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ['status' => $status, 'body' => $responseBody];
|
||||
}
|
||||
?>
|
||||
+9
-5
@@ -59,6 +59,7 @@ $stmt->execute($params);
|
||||
$orders = $stmt->fetchAll();
|
||||
|
||||
$logo_path = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'")->fetchColumn() ?: 'assets/default_logo.png';
|
||||
$csrf_token = getCsrfToken();
|
||||
|
||||
function getStatusClass($status) {
|
||||
return match($status) {
|
||||
@@ -102,7 +103,7 @@ function getStatusClass($status) {
|
||||
|
||||
<a class="navbar-brand d-flex align-items-center m-0" href="index.php">
|
||||
<?php if(file_exists($logo_path)): ?>
|
||||
<img src="<?php echo $logo_path; ?>" alt="Logo" class="logo-img">
|
||||
<img src="<?php echo e($logo_path); ?>" alt="Logo" class="logo-img">
|
||||
<?php else: ?>
|
||||
<span class="fs-4">💻</span>
|
||||
<?php endif; ?>
|
||||
@@ -114,7 +115,7 @@ function getStatusClass($status) {
|
||||
|
||||
<div class="d-flex ms-auto align-items-center gap-2">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="toggleDarkMode()"><i class="bi bi-moon-stars" id="themeIcon"></i></button>
|
||||
<span class="text-light small d-none d-lg-inline me-2">Witaj, <strong><?php echo $_SESSION['username']; ?></strong></span>
|
||||
<span class="text-light small d-none d-lg-inline me-2">Witaj, <strong><?php echo e($_SESSION['username']); ?></strong></span>
|
||||
<a class="btn btn-outline-light btn-sm" href="change_password.php"><i class="bi bi-key"></i> Hasło</a>
|
||||
<?php if ($_SESSION['role'] === 'admin'): ?>
|
||||
<a class="btn btn-outline-warning btn-sm" href="admin.php"><i class="bi bi-gear"></i> Admin</a>
|
||||
@@ -193,6 +194,7 @@ function getStatusClass($status) {
|
||||
</div>
|
||||
|
||||
<form method="POST" id="bulkForm">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="table-container p-0 overflow-hidden mb-3">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0 align-middle">
|
||||
@@ -421,6 +423,8 @@ function getStatusClass($status) {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const csrfToken = <?php echo json_encode($csrf_token); ?>;
|
||||
|
||||
async function performAction(orderId, actionType) {
|
||||
let confirmMsg = actionType === 'archive'
|
||||
? "Czy na pewno chcesz przenieść to zamówienie do archiwum?"
|
||||
@@ -432,7 +436,7 @@ function getStatusClass($status) {
|
||||
let response = await fetch('ajax_action.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: orderId, action: actionType })
|
||||
body: JSON.stringify({ id: orderId, action: actionType, csrf_token: csrfToken })
|
||||
});
|
||||
let resData = await response.json();
|
||||
|
||||
@@ -517,7 +521,7 @@ function getStatusClass($status) {
|
||||
let response = await fetch('ajax_edit.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id: orderId, field: fieldName, value: newValue })
|
||||
body: JSON.stringify({ id: orderId, field: fieldName, value: newValue, csrf_token: csrfToken })
|
||||
});
|
||||
let resData = await response.json();
|
||||
if(resData.success) {
|
||||
@@ -582,7 +586,7 @@ function getStatusClass($status) {
|
||||
let response = await fetch('ajax_add_row.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ product_name: prod, quantity: qty, purchase_place: place, price_per_unit: price })
|
||||
body: JSON.stringify({ product_name: prod, quantity: qty, purchase_place: place, price_per_unit: price, csrf_token: csrfToken })
|
||||
});
|
||||
let resData = await response.json();
|
||||
|
||||
|
||||
+41
-40
@@ -1,62 +1,57 @@
|
||||
<?php
|
||||
// 1. Włączenie raportowania błędów (na czas testów)
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
ini_set('display_errors', '0');
|
||||
ini_set('display_startup_errors', '0');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// 2. Start sesji - musi być na samym początku, przed jakimkolwiek znakiem!
|
||||
session_start();
|
||||
|
||||
// 3. Połączenie z bazą danych
|
||||
require_once 'includes/db.php';
|
||||
require_once 'includes/auth.php';
|
||||
require_once 'includes/oauth_microsoft.php';
|
||||
|
||||
$error = '';
|
||||
$logo_path = '';
|
||||
|
||||
// Pobranie ścieżki do logo z bazy danych
|
||||
if (isset($_GET['oauth_error'])) {
|
||||
$error = trim((string)$_GET['oauth_error']);
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT setting_value FROM " . DB_PREFIX . "settings WHERE setting_key = 'logo_path'");
|
||||
if ($stmt) {
|
||||
$logo_path = $stmt->fetchColumn();
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Ignorujemy błąd, jeśli tabela jeszcze nie istnieje itp.
|
||||
error_log($e->getMessage());
|
||||
}
|
||||
|
||||
// 4. Obsługa logowania
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$username = trim($_POST['username']);
|
||||
$password = $_POST['password'];
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
requireCsrfToken();
|
||||
|
||||
if (!empty($username) && !empty($password)) {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if ($username !== '' && $password !== '') {
|
||||
try {
|
||||
// Pobieranie użytkownika z bazy (uwzględniając prefix)
|
||||
$stmt = $pdo->prepare("SELECT * FROM " . DB_PREFIX . "users WHERE username = ?");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user) {
|
||||
// Weryfikacja hasła
|
||||
if (password_verify($password, $user['password'])) {
|
||||
// Logowanie udane - zapis do sesji
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
|
||||
// Przekierowanie do index.php
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
} else {
|
||||
$error = "Błędne hasło. Upewnij się, że hasło jest poprawne).";
|
||||
}
|
||||
} else {
|
||||
$error = "Użytkownik '$username' nie istnieje w bazie.";
|
||||
header("Location: index.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$error = "Nieprawidlowy login lub haslo.";
|
||||
} catch (PDOException $e) {
|
||||
$error = "Błąd bazy danych: " . $e->getMessage();
|
||||
error_log($e->getMessage());
|
||||
$error = "Nie udalo sie zalogowac. Sprobuj ponownie pozniej.";
|
||||
}
|
||||
} else {
|
||||
$error = "Proszę wypełnić oba pola.";
|
||||
$error = "Prosze wypelnic oba pola.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -66,7 +61,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Logowanie - <?php echo defined('APP_NAME') ? APP_NAME : 'System Zamówień'; ?></title>
|
||||
<title>Logowanie - <?php echo e(defined('APP_NAME') ? APP_NAME : 'System Zamowien'); ?></title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { background-color: #f4f7f6; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
||||
@@ -80,29 +75,35 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
<div class="login-card">
|
||||
<div class="text-center mb-4">
|
||||
<?php if ($logo_path && file_exists($logo_path)): ?>
|
||||
<img src="<?php echo htmlspecialchars($logo_path); ?>" alt="Logo" class="login-logo">
|
||||
<img src="<?php echo e($logo_path); ?>" alt="Logo" class="login-logo">
|
||||
<?php else: ?>
|
||||
<h3>💻 Logowanie</h3>
|
||||
<h3>Logowanie</h3>
|
||||
<?php endif; ?>
|
||||
<p class="text-muted small">Wpisz dane, aby zarządzać zamówieniami</p>
|
||||
<p class="text-muted small">Wpisz dane, aby zarzadzac zamowieniami</p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger p-2 small"><?php echo $error; ?></div>
|
||||
<div class="alert alert-danger p-2 small"><?php echo e($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="login.php">
|
||||
<?php echo csrfInput(); ?>
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label small">Użytkownik</label>
|
||||
<label for="username" class="form-label small">Uzytkownik</label>
|
||||
<input type="text" name="username" id="username" class="form-control" required autofocus>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label small">Hasło</label>
|
||||
<label for="password" class="form-label small">Haslo</label>
|
||||
<input type="password" name="password" id="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Zaloguj się</button>
|
||||
<button type="submit" class="btn btn-primary w-100">Zaloguj sie</button>
|
||||
</form>
|
||||
|
||||
<?php if (isMicrosoftOAuthConfigured()): ?>
|
||||
<div class="text-center my-3 text-muted small">lub</div>
|
||||
<a href="oauth_login.php" class="btn btn-outline-dark w-100">Zaloguj przez Microsoft 365</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mt-4 text-center border-top pt-3">
|
||||
<p class="text-muted" style="font-size: 0.8rem;">
|
||||
Aplikacja: <strong>goral.edu.pl/zeszyt</strong><br>
|
||||
|
||||
+1
-6
@@ -1,14 +1,9 @@
|
||||
<?php
|
||||
// 1. Rozpoczęcie sesji, aby mieć do niej dostęp
|
||||
session_start();
|
||||
|
||||
// 2. Usunięcie wszystkich zmiennych sesyjnych (user_id, role, username)
|
||||
session_unset();
|
||||
|
||||
// 3. Całkowite zniszczenie sesji na serwerze
|
||||
unset($_SESSION['microsoft_oauth_state'], $_SESSION['microsoft_oauth_nonce']);
|
||||
session_destroy();
|
||||
|
||||
// 4. Przekierowanie użytkownika do strony logowania
|
||||
header("Location: login.php");
|
||||
exit();
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
require_once 'includes/oauth_microsoft.php';
|
||||
|
||||
if (!isMicrosoftOAuthConfigured()) {
|
||||
http_response_code(503);
|
||||
exit('Logowanie Microsoft nie jest skonfigurowane.');
|
||||
}
|
||||
|
||||
$expectedState = $_SESSION['microsoft_oauth_state'] ?? null;
|
||||
$state = $_GET['state'] ?? '';
|
||||
$code = $_GET['code'] ?? '';
|
||||
$error = $_GET['error'] ?? '';
|
||||
|
||||
unset($_SESSION['microsoft_oauth_state']);
|
||||
|
||||
if ($error !== '') {
|
||||
header('Location: login.php?oauth_error=' . urlencode('Logowanie Microsoft zostalo anulowane lub odrzucone.'));
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!$expectedState || !hash_equals($expectedState, (string)$state) || $code === '') {
|
||||
header('Location: login.php?oauth_error=' . urlencode('Nieprawidlowy stan logowania Microsoft.'));
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$tokens = exchangeMicrosoftCodeForTokens($code);
|
||||
$identity = extractMicrosoftIdentity($tokens);
|
||||
$user = findOrProvisionMicrosoftUser($pdo, $identity);
|
||||
loginUserIntoSession($user);
|
||||
header('Location: index.php');
|
||||
exit();
|
||||
} catch (Throwable $e) {
|
||||
error_log($e->getMessage());
|
||||
header('Location: login.php?oauth_error=' . urlencode('Nie udalo sie zalogowac przez Microsoft 365.'));
|
||||
exit();
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
require_once 'includes/oauth_microsoft.php';
|
||||
|
||||
if (!isMicrosoftOAuthConfigured()) {
|
||||
http_response_code(503);
|
||||
exit('Logowanie Microsoft nie jest skonfigurowane.');
|
||||
}
|
||||
|
||||
header('Location: ' . buildMicrosoftAuthorizationUrl());
|
||||
exit();
|
||||
?>
|
||||
+2
-1
@@ -4,6 +4,7 @@ require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
requireCsrfToken();
|
||||
$ids = $_POST['order_ids'];
|
||||
$placeholders = str_repeat('?,', count($ids) - 1) . '?';
|
||||
$cols = $_POST['print_cols'] ?? ['id', 'product', 'quantity', 'place', 'price', 'status'];
|
||||
@@ -82,7 +83,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
<?php if($hasCol('quantity')): ?> <td style="text-align: center;"><strong><?php echo $o['quantity']; ?></strong></td> <?php endif; ?>
|
||||
<?php if($hasCol('place')): ?> <td><?php echo htmlspecialchars($o['purchase_place']); ?></td> <?php endif; ?>
|
||||
<?php if($hasCol('price')): ?> <td><?php echo number_format($o['price_per_unit'], 2, ',', ' '); ?> zł</td> <?php endif; ?>
|
||||
<?php if($hasCol('status')): ?> <td><?php echo $o['status']; ?></td> <?php endif; ?>
|
||||
<?php if($hasCol('status')): ?> <td><?php echo e($o['status']); ?></td> <?php endif; ?>
|
||||
</tr>
|
||||
|
||||
<?php if($hasCol('recipient') || $hasCol('address') || $hasCol('notes')): ?>
|
||||
|
||||
@@ -4,6 +4,7 @@ require_once 'includes/auth.php';
|
||||
checkAuth();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['order_ids'])) {
|
||||
requireCsrfToken();
|
||||
$ids = $_POST['order_ids'];
|
||||
$placeholders = str_repeat('?,', count($ids) - 1) . '?';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user