diff --git a/WorkflowEngine.php b/WorkflowEngine.php new file mode 100644 index 0000000..d777948 --- /dev/null +++ b/WorkflowEngine.php @@ -0,0 +1,263 @@ +pdo = db(); + } + + /** + * Pobiera wszystkie dane niezbędne dla głównej macierzy pulpitu procesów. + * + * @return array Tablica zawierająca 'people', 'definitions' i zmapowaną tablicę 'instances'. + */ + public function getDashboardMatrix(): array { + // Get all people (potential assignees) + $stmt_people = $this->pdo->prepare("SELECT id, firstName, lastName, companyName, role, email, phone FROM people ORDER BY lastName, firstName"); + $stmt_people->execute(); + $people = $stmt_people->fetchAll(PDO::FETCH_ASSOC); + + // Fetch all process definitions + $stmt_defs = $this->pdo->prepare("SELECT id, name FROM process_definitions ORDER BY name"); + $stmt_defs->execute(); + $process_definitions = $stmt_defs->fetchAll(PDO::FETCH_ASSOC); + + // Fetch instances + $stmt_instances = $this->pdo->prepare("SELECT * FROM process_instances"); + $stmt_instances->execute(); + $instances_data = $stmt_instances->fetchAll(PDO::FETCH_ASSOC); + + $instances = []; + foreach ($instances_data as $instance) { + $instances[$instance['personId']][$instance['processDefinitionId']] = $instance; + } + + return [ + 'people' => $people, + 'definitions' => $process_definitions, + 'instances' => $instances, + ]; + } + + /** + * Rozpoczyna nową instancję procesu dla danej osoby. + * + * @param string $processCode Unikalny kod definicji procesu. + * @param int $personId ID osoby. + * @param int $userId ID użytkownika inicjującego akcję. + * @return int|null ID nowo utworzonej instancji lub null w przypadku niepowodzenia. + */ + public function startProcess(string $processCode, int $personId, int $userId): ?int { + // 1. Znajdź aktywną definicję procesu po kodzie. + // 2. Pobierz start_node_id z definicji. + // 3. Utwórz nową instancję procesu ze statusem 'in_progress' i current_node_id. + // 4. Utwórz zdarzenie systemowe dla rozpoczęcia procesu. + // TODO: Implementacja logiki. + return null; + } + + /** + * Pobiera pojedynczą instancję procesu, tworząc ją, jeśli nie istnieje. + * + * @param int $personId + * @param int $processDefinitionId + * @param int $userId Użytkownik inicjujący utworzenie, jeśli to nastąpi. + * @return array|null Tablica asocjacyjna z danymi instancji. + */ + public function getOrCreateInstanceByDefId(int $personId, int $processDefinitionId, int $userId): ?array { + $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE personId = ? AND processDefinitionId = ?"); + $stmt->execute([$personId, $processDefinitionId]); + $instance = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$instance) { + // Fetch the process definition to get the initial status + $stmt_def = $this->pdo->prepare("SELECT definition_json FROM process_definitions WHERE id = ?"); + $stmt_def->execute([$processDefinitionId]); + $definition_raw = $stmt_def->fetchColumn(); + $definition = $definition_raw ? json_decode($definition_raw, true) : null; + $initial_status = $definition['initial_status'] ?? 'none'; + + $stmt_insert = $this->pdo->prepare("INSERT INTO process_instances (personId, processDefinitionId, current_status) VALUES (?, ?, ?)"); + $stmt_insert->execute([$personId, $processDefinitionId, $initial_status]); + $instanceId = $this->pdo->lastInsertId(); + + // Utwórz zdarzenie systemowe dla utworzenia instancji + $this->addEvent($instanceId, 'system', 'Instancja utworzona.', null, [], $userId); + + // Pobierz ponownie nowo utworzoną instancję + $stmt->execute([$personId, $processDefinitionId]); + $instance = $stmt->fetch(PDO::FETCH_ASSOC); + } + + return $instance; + } + + /** + * Dodaje nowe zdarzenie do historii instancji. + * To jest wewnętrzna metoda pomocnicza. + */ + private function addEvent(int $instanceId, string $eventType, string $message, ?string $nodeId, array $payload, int $userId): void { + $stmt = $this->pdo->prepare( + "INSERT INTO process_events (processInstanceId, event_type, message, node_id, payload_json, createdById) VALUES (?, ?, ?, ?, ?, ?)" + ); + $stmt->execute([$instanceId, $eventType, $message, $nodeId, json_encode($payload), $userId]); + } + + /** + * Pobiera historię zdarzeń dla danej instancji. + * + * @param int $instanceId + * @return array + */ + public function getEvents(int $instanceId): array { + $stmt_events = $this->pdo->prepare("SELECT pe.*, p.email as user_email, p.firstName, p.lastName FROM process_events pe JOIN people p ON pe.createdById = p.id WHERE pe.processInstanceId = ? ORDER BY pe.createdAt DESC"); + $stmt_events->execute([$instanceId]); + return $stmt_events->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * Pobiera listę dostępnych przejść z bieżącego węzła instancji. + * + * @param int $instanceId + * @return array Lista dostępnych przejść. + */ + public function getAvailableTransitions(int $instanceId): array { + $stmt = $this->pdo->prepare( + 'SELECT pi.current_status, pd.definition_json ' + . 'FROM process_instances pi ' + . 'JOIN process_definitions pd ON pi.processDefinitionId = pd.id ' + . 'WHERE pi.id = ?' + ); + $stmt->execute([$instanceId]); + $result = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$result || empty($result['definition_json'])) { + return []; + } + + $definition = json_decode($result['definition_json'], true); + if (!$definition || !isset($definition['transitions'])) { + return []; + } + + $current_status = $result['current_status']; + $allowed_transitions = $definition['transitions'][$current_status] ?? []; + + $transitions = []; + foreach ($allowed_transitions as $target_status) { + $transitions[] = [ + 'id' => 'transition_' . str_replace(' ', '_', strtolower($target_status)), // e.g., transition_in_progress + 'name' => 'Oznacz jako ' . $target_status, // e.g., Oznacz jako In Progress + 'target_status' => $target_status + ]; + } + + return $transitions; + } + + /** + * Stosuje przejście do instancji procesu. To jest główna metoda do postępu w przepływie pracy. + * + * @param int $instanceId ID instancji procesu. + * @param string $transitionId ID przejścia do zastosowania (z definition_json). + * @param array $inputPayload Dane zebrane od użytkownika dla tego kroku. + * @param int $userId ID użytkownika wykonującego akcję. + * @return bool True w przypadku sukcesu, false w przypadku porażki. + */ + public function applyTransition(int $instanceId, string $transitionId, array $inputPayload, int $userId): bool { + $this->pdo->beginTransaction(); + + try { + // 1. Pobierz instancję i dostępne przejścia + $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE id = ?"); + $stmt->execute([$instanceId]); + $instance = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$instance) { + // Instancja nie znaleziona + $this->pdo->rollBack(); + return false; + } + + $availableTransitions = $this->getAvailableTransitions($instanceId); + + // 2. Sprawdź, czy przejście jest dozwolone + $selectedTransition = null; + if ($transitionId === 'note') { // Specjalny przypadek dodawania notatki + $selectedTransition = ['id' => 'note', 'name' => 'Dodano notatkę', 'target_status' => $instance['current_status']]; + } else { + foreach ($availableTransitions as $trans) { + if ($trans['id'] === $transitionId) { + $selectedTransition = $trans; + break; + } + } + } + + if (!$selectedTransition) { + // Nieprawidłowe lub niedozwolone przejście + $this->pdo->rollBack(); + return false; + } + + // 3. Utwórz zdarzenie + $eventType = ($transitionId === 'note') ? 'note' : 'transition_applied'; + $message = $inputPayload['message'] ?? $selectedTransition['name']; + $this->addEvent($instanceId, $eventType, $message, null, $inputPayload, $userId); + + // 4. Zaktualizuj instancję + $stmt_update = $this->pdo->prepare( + "UPDATE process_instances SET current_status = ?, lastActivityAt = CURRENT_TIMESTAMP WHERE id = ?" + ); + $stmt_update->execute([$selectedTransition['target_status'], $instanceId]); + + $this->pdo->commit(); + return true; + + } catch (Exception $e) { + $this->pdo->rollBack(); + error_log("Błąd w applyTransition: " . $e->getMessage()); + return false; + } + } + + /** + * Masowa operacja stosowania tego samego przejścia do wielu osób dla danego procesu. + * + * @param string $processCode + * @param array $personIds + * @param string $transitionId + * @param array $inputPayload + * @param int $userId + * @return array Podsumowanie wyników (np. ['success' => count, 'failed' => count]). + */ + public function bulkApplyTransition(string $processCode, array $personIds, string $transitionId, array $inputPayload, int $userId): array { + // 1. Upewnij się, że instancje istnieją dla wszystkich osób (użyj ensureInstances). + // 2. Przejdź przez pętlę personIds i wywołaj applyTransition dla każdej z nich. + // TODO: Implementacja logiki. + return ['success' => 0, 'failed' => 0]; + } + + /** + * Zapewnia, że instancje procesów istnieją dla danego zestawu osób i kodów procesów. + * Jeśli instancja brakuje, zostanie utworzona. + * + * @param array $personIds + * @param array $processCodes + * @param int $userId + * @return array Podsumowanie utworzonych instancji. + */ + public function ensureInstances(array $personIds, array $processCodes, int $userId): array { + // TODO: Implementacja logiki do tworzenia brakujących instancji. + return ['created' => 0]; + } +} \ No newline at end of file diff --git a/_add_bni_group.php b/_add_bni_group.php new file mode 100644 index 0000000..015fcaf --- /dev/null +++ b/_add_bni_group.php @@ -0,0 +1,32 @@ +prepare("INSERT INTO bni_groups (name, city, active, display_order) VALUES (:name, :city, :active, :display_order)"); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':city', $city); + $stmt->bindParam(':active', $active, PDO::PARAM_INT); + $stmt->bindParam(':display_order', $display_order, PDO::PARAM_INT); + $stmt->execute(); + + $_SESSION['success_message'] = 'BNI Group added successfully!'; + } catch (PDOException $e) { + $_SESSION['error_message'] = 'Error adding BNI group: ' . $e->getMessage(); + } +} + +header('Location: bni_groups.php'); +exit; diff --git a/_add_calendar_event.php b/_add_calendar_event.php new file mode 100644 index 0000000..036b889 --- /dev/null +++ b/_add_calendar_event.php @@ -0,0 +1,88 @@ +beginTransaction(); + + // Insert the main event + $stmt = $pdo->prepare("INSERT INTO calendar_events (title, description, start_datetime, end_datetime, event_type_id, recurrence, recurrence_end_date) VALUES (?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$title, $description, $start_datetime, $end_datetime, $event_type_id, $recurrence, $recurrence_end_date]); + $parent_event_id = $pdo->lastInsertId(); + + if ($recurrence && !empty($recurrence_end_date)) { + $start_date = new DateTime($start_datetime); + $end_date = new DateTime($end_datetime); + $recurrence_end = new DateTime($recurrence_end_date); + $interval_spec = ''; + + switch ($recurrence) { + case 'daily': + $interval_spec = 'P1D'; + break; + case 'weekly': + $interval_spec = 'P1W'; + break; + case 'monthly': + $interval_spec = 'P1M'; + break; + } + + if ($interval_spec) { + $interval = new DateInterval($interval_spec); + $period_start = clone $start_date; + $period_start->add($interval); + + $period = new DatePeriod($period_start, $interval, $recurrence_end); + + $stmt_recur = $pdo->prepare("INSERT INTO calendar_events (title, description, start_datetime, end_datetime, event_type_id, parent_event_id) VALUES (?, ?, ?, ?, ?, ?)"); + + foreach ($period as $date) { + $new_start_datetime = $date->format('Y-m-d H:i:s'); + $end_date_clone = clone $date; + $new_end_datetime = $end_date_clone->add($start_date->diff($end_date))->format('Y-m-d H:i:s'); + $stmt_recur->execute([$title, $description, $new_start_datetime, $new_end_datetime, $event_type_id, $parent_event_id]); + } + } + } + + $pdo->commit(); + header("Location: calendar.php"); + exit(); + + } catch (Exception $e) { + $pdo->rollBack(); + error_log($e->getMessage()); + header("Location: calendar.php?error=db_error"); + exit(); + } +} diff --git a/_add_event_type.php b/_add_event_type.php new file mode 100644 index 0000000..d7db0bc --- /dev/null +++ b/_add_event_type.php @@ -0,0 +1,18 @@ +prepare("INSERT INTO event_types (name, color, display_order) VALUES (?, ?, ?)"); + $stmt->execute([$name, $color, $display_order]); + + session_start(); + $_SESSION['success_message'] = 'Event type added successfully.'; + header('Location: event_types.php'); + exit; +} +?> \ No newline at end of file diff --git a/_add_function.php b/_add_function.php new file mode 100644 index 0000000..4d16b79 --- /dev/null +++ b/_add_function.php @@ -0,0 +1,21 @@ +prepare("functions (name, display_order) VALUES (:name, :display_order)"); + $stmt->execute(['name' => $name, 'display_order' => $display_order]); + } +} + +header('Location: roles.php'); +exit(); diff --git a/_add_process_event.php b/_add_process_event.php new file mode 100644 index 0000000..14344a4 --- /dev/null +++ b/_add_process_event.php @@ -0,0 +1,31 @@ +prepare("INSERT INTO process_events (processInstanceId, eventType, description, createdBy) VALUES (?, ?, ?, ?)"); +$stmt->execute([$instanceId, $eventType, $description, $userId]); + +// Update the last activity time for the instance +$stmt_update = $pdo->prepare("UPDATE process_instances SET lastActivityAt = NOW() WHERE id = ?"); +$stmt_update->execute([$instanceId]); + +// Redirect back to the dashboard +header("Location: process_dashboard.php"); +exit; diff --git a/_apply_transition.php b/_apply_transition.php new file mode 100644 index 0000000..34621ca --- /dev/null +++ b/_apply_transition.php @@ -0,0 +1,43 @@ + 'danger', 'message' => 'Błąd: Brak wymaganych parametrów.']; + header('Location: process_dashboard.php'); + exit; +} + +$instanceId = (int)$_POST['instanceId']; +$transitionId = $_POST['transitionId']; +$userId = $_SESSION['user_id'] ?? null; +$payload = $_POST['payload'] ?? null; + +if (!$userId) { + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Błąd: Sesja wygasła.']; + header('Location: login.php'); + exit; +} + +try { + $engine = new WorkflowEngine(); + $success = $engine->applyTransition($instanceId, $transitionId, $payload, $userId); + + if ($success) { + $_SESSION['flash_message'] = ['type' => 'success', 'message' => 'Akcja została wykonana pomyślnie.']; + } else { + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Błąd: Nie udało się wykonać akcji.']; + } +} catch (Exception $e) { + error_log("Error applying transition: " . $e->getMessage()); + $_SESSION['flash_message'] = ['type' => 'danger', 'message' => 'Wystąpił krytyczny błąd: ' . $e->getMessage()]; +} + +header('Location: process_dashboard.php'); +exit; \ No newline at end of file diff --git a/_bulk_add_event.php b/_bulk_add_event.php new file mode 100644 index 0000000..6c554a7 --- /dev/null +++ b/_bulk_add_event.php @@ -0,0 +1,53 @@ +prepare("SELECT id FROM process_instances WHERE processDefinitionId = ? AND personId IN ($placeholders)"); +$params = array_merge([$process_id], $person_ids); +$stmt->execute($params); +$instance_ids = $stmt->fetchAll(PDO::FETCH_COLUMN); + +if (!empty($instance_ids)) { + $instance_placeholders = implode(',', array_fill(0, count($instance_ids), '?')); + + // Update last activity + $stmt_update = $pdo->prepare("UPDATE process_instances SET lastActivityAt = NOW() WHERE id IN ($instance_placeholders)"); + $stmt_update->execute($instance_ids); + + // Bulk insert events + $event_sql = "INSERT INTO process_events (processInstanceId, event_type, message, createdById) VALUES "; + $event_rows = []; + $event_params = []; + foreach($instance_ids as $instance_id) { + $event_rows[] = "(?, 'note', ?, ?)"; + $event_params[] = $instance_id; + $event_params[] = $message; + $event_params[] = $userId; + } + $event_sql .= implode(', ', $event_rows); + $stmt_event = $pdo->prepare($event_sql); + $stmt_event->execute($event_params); +} + +$_SESSION['flash_message'] = "Bulk event addition completed."; +header('Location: process_dashboard.php'); +exit; diff --git a/_bulk_init_instances.php b/_bulk_init_instances.php new file mode 100644 index 0000000..fda7a2e --- /dev/null +++ b/_bulk_init_instances.php @@ -0,0 +1,33 @@ +prepare($sql); +$stmt->execute($params); + +$_SESSION['flash_message'] = "Bulk initialization completed."; +header('Location: process_dashboard.php'); +exit; diff --git a/_bulk_update_status.php b/_bulk_update_status.php new file mode 100644 index 0000000..060be43 --- /dev/null +++ b/_bulk_update_status.php @@ -0,0 +1,54 @@ +prepare("SELECT id FROM process_instances WHERE processDefinitionId = ? AND personId IN ($placeholders)"); +$params = array_merge([$process_id], $person_ids); +$stmt->execute($params); +$instance_ids = $stmt->fetchAll(PDO::FETCH_COLUMN); + +if (!empty($instance_ids)) { + $instance_placeholders = implode(',', array_fill(0, count($instance_ids), '?')); + + // Update statuses + $stmt_update = $pdo->prepare("UPDATE process_instances SET current_status = ?, lastActivityAt = NOW() WHERE id IN ($instance_placeholders)"); + $stmt_update->execute(array_merge([$status], $instance_ids)); + + // Bulk insert events + $event_sql = "INSERT INTO process_events (processInstanceId, event_type, message, createdById) VALUES "; + $event_rows = []; + $event_params = []; + $message = "Status changed to $status"; + foreach($instance_ids as $instance_id) { + $event_rows[] = "(?, 'status_change', ?, ?)"; + $event_params[] = $instance_id; + $event_params[] = $message; + $event_params[] = $userId; + } + $event_sql .= implode(', ', $event_rows); + $stmt_event = $pdo->prepare($event_sql); + $stmt_event->execute($event_params); +} + +$_SESSION['flash_message'] = "Bulk status update completed."; +header('Location: process_dashboard.php'); +exit; diff --git a/_create_person.php b/_create_person.php new file mode 100644 index 0000000..e904bf5 --- /dev/null +++ b/_create_person.php @@ -0,0 +1,53 @@ +prepare($sql); + $stmt->execute([$firstName, $lastName, $email, password_hash($password, PASSWORD_DEFAULT), $companyName, $phone, $role]); + $personId = $pdo->lastInsertId(); + + // Assign functions + if (!empty($functions)) { + $sql = "INSERT INTO user_functions (user_id, function_id) VALUES (?, ?)"; + $stmt = $pdo->prepare($sql); + foreach ($functions as $functionId) { + $stmt->execute([$personId, $functionId]); + } + } + + $_SESSION['success_message'] = 'Osoba dodana pomyślnie.'; + + } catch (PDOException $e) { + error_log('Create failed: ' . $e->getMessage()); + if ($e->errorInfo[1] == 1062) { + $_SESSION['error_message'] = 'Błąd: Konto z tym adresem email już istnieje.'; + } else { + $_SESSION['error_message'] = 'Błąd podczas dodawania osoby.'; + } + } + + header('Location: index.php'); + exit(); +} +?> \ No newline at end of file diff --git a/_delete_bni_group.php b/_delete_bni_group.php new file mode 100644 index 0000000..e6a55e9 --- /dev/null +++ b/_delete_bni_group.php @@ -0,0 +1,20 @@ +prepare("DELETE FROM bni_groups WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->execute(); + + $_SESSION['success_message'] = 'BNI Group deleted successfully!'; + } catch (PDOException $e) { + $_SESSION['error_message'] = 'Error deleting BNI group: ' . $e->getMessage(); + } +} + +header('Location: bni_groups.php'); +exit; diff --git a/_delete_calendar_event.php b/_delete_calendar_event.php new file mode 100644 index 0000000..8d96636 --- /dev/null +++ b/_delete_calendar_event.php @@ -0,0 +1,48 @@ +beginTransaction(); + + // Check if the event is a parent event + $stmt = $pdo->prepare("SELECT parent_event_id FROM calendar_events WHERE id = ?"); + $stmt->execute([$event_id]); + $event = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($event) { + if ($event['parent_event_id'] === null) { + // It's a parent event, delete it and all its children + $stmt_delete_children = $pdo->prepare("DELETE FROM calendar_events WHERE parent_event_id = ?"); + $stmt_delete_children->execute([$event_id]); + } + + // Delete the event itself + $stmt_delete = $pdo->prepare("DELETE FROM calendar_events WHERE id = ?"); + $stmt_delete->execute([$event_id]); + } + + $pdo->commit(); + header("Location: calendar.php"); + exit(); + + } catch (Exception $e) { + $pdo->rollBack(); + error_log($e->getMessage()); + header("Location: calendar.php?error=db_error"); + exit(); + } +} else { + header("Location: calendar.php"); + exit(); +} diff --git a/_delete_event_type.php b/_delete_event_type.php new file mode 100644 index 0000000..868a28c --- /dev/null +++ b/_delete_event_type.php @@ -0,0 +1,16 @@ +prepare("DELETE FROM event_types WHERE id = ?"); + $stmt->execute([$id]); + + session_start(); + $_SESSION['success_message'] = 'Event type deleted successfully.'; + header('Location: event_types.php'); + exit; +} +?> \ No newline at end of file diff --git a/_delete_function.php b/_delete_function.php new file mode 100644 index 0000000..bb5b1c1 --- /dev/null +++ b/_delete_function.php @@ -0,0 +1,21 @@ +prepare("DELETE FROM functions WHERE id = :id"); +$stmt->execute(['id' => $id]); + +// Optional: Also delete user_functions associated with this function +$stmt = $pdo->prepare("DELETE FROM user_functions WHERE function_id = :function_id"); +$stmt->execute(['function_id' => $id]); + +header('Location: functions.php'); +exit(); diff --git a/_delete_person.php b/_delete_person.php new file mode 100644 index 0000000..2b824f5 --- /dev/null +++ b/_delete_person.php @@ -0,0 +1,16 @@ +prepare("DELETE FROM people WHERE id = ?"); + $stmt->execute([$id]); + + $_SESSION['success_message'] = 'Osoba usunięta pomyślnie.'; + header('Location: persons.php'); + exit; +} +?> \ No newline at end of file diff --git a/_footer.php b/_footer.php new file mode 100644 index 0000000..6ec3293 --- /dev/null +++ b/_footer.php @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/_get_event_details.php b/_get_event_details.php new file mode 100644 index 0000000..fb9be1a --- /dev/null +++ b/_get_event_details.php @@ -0,0 +1,26 @@ +prepare("SELECT c.*, t.name as type_name FROM calendar_events c LEFT JOIN event_types t ON c.event_type_id = t.id WHERE c.id = ?"); + $stmt->execute([$event_id]); + $event = $stmt->fetch(PDO::FETCH_ASSOC); + + if ($event) { + header('Content-Type: application/json'); + echo json_encode($event); + } else { + header("HTTP/1.1 404 Not Found"); + } +} else { + header("HTTP/1.1 400 Bad Request"); +} diff --git a/_get_instance_details.php b/_get_instance_details.php new file mode 100644 index 0000000..d2938e0 --- /dev/null +++ b/_get_instance_details.php @@ -0,0 +1,88 @@ +getOrCreateInstanceByDefId($personId, $processDefinitionId, $userId); +if (!$instance) { + http_response_code(500); + die('Nie można pobrać lub utworzyć instancji procesu.'); +} +$instanceId = $instance['id']; + +// 2. Pobierz powiązane dane przez silnik +$events = $engine->getEvents($instanceId); +$availableTransitions = $engine->getAvailableTransitions($instanceId); + +// 3. Pobierz nazwy do wyświetlenia +$pdo = db(); +$stmt_person = $pdo->prepare("SELECT firstName, lastName FROM people WHERE id = ?"); +$stmt_person->execute([$personId]); +$person = $stmt_person->fetch(); + +$stmt_process = $pdo->prepare("SELECT name FROM process_definitions WHERE id = ?"); +$stmt_process->execute([$processDefinitionId]); +$process = $stmt_process->fetch(); +?> + +

-

+

Status:

+
+ +
Wykonaj akcję
+
+ +
+ + +
+
+ + +
+ +
+ +
+ +
Historia
+ +

Brak zdarzeń.

+ + + \ No newline at end of file diff --git a/_get_person_details.php b/_get_person_details.php new file mode 100644 index 0000000..026fa7b --- /dev/null +++ b/_get_person_details.php @@ -0,0 +1,32 @@ +prepare("SELECT * FROM people WHERE id = ?"); + $stmt->execute([$person_id]); + $person = $stmt->fetch(PDO::FETCH_ASSOC); + + // Fetch all functions + $stmt = $pdo->query("SELECT id, name FROM functions ORDER BY display_order"); + $all_functions = $stmt->fetchAll(PDO::FETCH_ASSOC); + + // Fetch person's functions + $stmt = $pdo->prepare("SELECT function_id FROM user_functions WHERE user_id = ?"); + $stmt->execute([$person_id]); + $person_functions = $stmt->fetchAll(PDO::FETCH_COLUMN, 0); + + $response = [ + 'person' => $person, + 'all_functions' => $all_functions, + 'person_functions' => $person_functions + ]; + + header('Content-Type: application/json'); + echo json_encode($response); + exit; +} +?> \ No newline at end of file diff --git a/_header.php b/_header.php new file mode 100644 index 0000000..fc22757 --- /dev/null +++ b/_header.php @@ -0,0 +1,44 @@ + + + + + + + <?php echo getenv('PROJECT_NAME') ?: 'My App'; ?> - Dashboard + + + + + + + + + + + + + + + + + + + + "> + + + + + + + + + + diff --git a/_init_instances.php b/_init_instances.php new file mode 100644 index 0000000..6f157d9 --- /dev/null +++ b/_init_instances.php @@ -0,0 +1,37 @@ +prepare("SELECT id FROM people WHERE active = 1"); +$stmt_people->execute(); +$people = $stmt_people->fetchAll(PDO::FETCH_COLUMN); + +// Get all active process definitions +$stmt_processes = $pdo->prepare("SELECT id FROM process_definitions WHERE is_active = 1"); +$stmt_processes->execute(); +$processes = $stmt_processes->fetchAll(PDO::FETCH_COLUMN); + +$insert_stmt = $pdo->prepare("INSERT IGNORE INTO process_instances (personId, processDefinitionId, current_status) VALUES (?, ?, 'none')"); + +$count = 0; +foreach ($people as $personId) { + foreach ($processes as $processId) { + $insert_stmt->execute([$personId, $processId]); + if ($insert_stmt->rowCount() > 0) { + $count++; + } + } +} + +$_SESSION['flash_message'] = "Initialized $count new process instances."; + +header("Location: process_dashboard.php"); // Redirect to the main dashboard +exit; diff --git a/_navbar.php b/_navbar.php new file mode 100644 index 0000000..6e71f49 --- /dev/null +++ b/_navbar.php @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/_save_process_definition.php b/_save_process_definition.php new file mode 100644 index 0000000..65fc887 --- /dev/null +++ b/_save_process_definition.php @@ -0,0 +1,49 @@ +prepare($sql); + $stmt->execute($params); + + session_start(); + $_SESSION['success_message'] = $message; + + } catch (PDOException $e) { + error_log('Save process definition failed: ' . $e->getMessage()); + die('Save process definition failed. Please check the logs.'); + } + + header('Location: process_definitions.php'); + exit(); +} diff --git a/_sidebar.php b/_sidebar.php new file mode 100644 index 0000000..f0bd2e6 --- /dev/null +++ b/_sidebar.php @@ -0,0 +1,56 @@ + + \ No newline at end of file diff --git a/_update_bni_group.php b/_update_bni_group.php new file mode 100644 index 0000000..e66be93 --- /dev/null +++ b/_update_bni_group.php @@ -0,0 +1,34 @@ +prepare("UPDATE bni_groups SET name = :name, city = :city, active = :active, display_order = :display_order WHERE id = :id"); + $stmt->bindParam(':id', $id, PDO::PARAM_INT); + $stmt->bindParam(':name', $name); + $stmt->bindParam(':city', $city); + $stmt->bindParam(':active', $active, PDO::PARAM_INT); + $stmt->bindParam(':display_order', $display_order, PDO::PARAM_INT); + $stmt->execute(); + + $_SESSION['success_message'] = 'BNI Group updated successfully!'; + } catch (PDOException $e) { + $_SESSION['error_message'] = 'Error updating BNI group: ' . $e->getMessage(); + } +} + +header('Location: bni_groups.php'); +exit; diff --git a/_update_bni_group_order.php b/_update_bni_group_order.php new file mode 100644 index 0000000..854049b --- /dev/null +++ b/_update_bni_group_order.php @@ -0,0 +1,67 @@ +beginTransaction(); + + try { + foreach ($ordered_ids as $index => $id) { + $sql = "UPDATE bni_groups SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$index + 1, $id]); + } + $pdo->commit(); + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Order updated successfully.']); + exit(); + + } catch (PDOException $e) { + $pdo->rollBack(); + header('Content-Type: application/json'); + http_response_code(500); + echo json_encode(['success' => false, 'message' => 'Error updating display order: ' . $e->getMessage()]); + exit(); + } + } +} + +// Fallback for old form submission, though it's being deprecated +if (isset($_POST['ids']) && isset($_POST['display_order'])) { + $ids = $_POST['ids']; + $display_orders = $_POST['display_order']; + + if (count($ids) !== count($display_orders)) { + $_SESSION['error_message'] = "Something went wrong. Please try again."; + header("Location: bni_groups.php"); + exit(); + } + + $pdo = db(); + $pdo->beginTransaction(); + + try { + for ($i = 0; $i < count($ids); $i++) { + $sql = "UPDATE bni_groups SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$display_orders[$i], $ids[$i]]); + } + $pdo->commit(); + $_SESSION['success_message'] = "Display order updated successfully."; + } catch (PDOException $e) { + $pdo->rollBack(); + $_SESSION['error_message'] = "Error updating display order: " . $e->getMessage(); + } + + header("Location: bni_groups.php"); + exit(); +} + +http_response_code(400); +header('Content-Type: application/json'); +echo json_encode(['success' => false, 'message' => 'Invalid request.']); diff --git a/_update_calendar_event.php b/_update_calendar_event.php new file mode 100644 index 0000000..758e240 --- /dev/null +++ b/_update_calendar_event.php @@ -0,0 +1,40 @@ +prepare("UPDATE calendar_events SET title = ?, description = ?, start_datetime = ?, end_datetime = ?, event_type_id = ? WHERE id = ?"); + + try { + $stmt->execute([$title, $description, $start_datetime, $end_datetime, $event_type_id, $event_id]); + header("Location: calendar.php"); + exit(); + } catch (PDOException $e) { + // Handle database error + error_log($e->getMessage()); + header("Location: calendar.php?error=db_error"); + exit(); + } +} \ No newline at end of file diff --git a/_update_event_type.php b/_update_event_type.php new file mode 100644 index 0000000..8d9cee2 --- /dev/null +++ b/_update_event_type.php @@ -0,0 +1,19 @@ +prepare("UPDATE event_types SET name = ?, color = ?, display_order = ? WHERE id = ?"); + $stmt->execute([$name, $color, $display_order, $id]); + + session_start(); + $_SESSION['success_message'] = 'Event type updated successfully.'; + header('Location: event_types.php'); + exit; +} +?> \ No newline at end of file diff --git a/_update_event_type_order.php b/_update_event_type_order.php new file mode 100644 index 0000000..0652ba3 --- /dev/null +++ b/_update_event_type_order.php @@ -0,0 +1,67 @@ +beginTransaction(); + + try { + foreach ($ordered_ids as $index => $id) { + $sql = "UPDATE event_types SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$index + 1, $id]); + } + $pdo->commit(); + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Order updated successfully.']); + exit(); + + } catch (PDOException $e) { + $pdo->rollBack(); + header('Content-Type: application/json'); + http_response_code(500); + echo json_encode(['success' => false, 'message' => 'Error updating display order: ' . $e->getMessage()]); + exit(); + } + } +} + +// Fallback for old form submission, though it's being deprecated +if (isset($_POST['ids']) && isset($_POST['display_order'])) { + $ids = $_POST['ids']; + $display_orders = $_POST['display_order']; + + if (count($ids) !== count($display_orders)) { + $_SESSION['error_message'] = "Something went wrong. Please try again."; + header("Location: event_types.php"); + exit(); + } + + $pdo = db(); + $pdo->beginTransaction(); + + try { + for ($i = 0; $i < count($ids); $i++) { + $sql = "UPDATE event_types SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$display_orders[$i], $ids[$i]]); + } + $pdo->commit(); + $_SESSION['success_message'] = "Display order updated successfully."; + } catch (PDOException $e) { + $pdo->rollBack(); + $_SESSION['error_message'] = "Error updating display order: " . $e->getMessage(); + } + + header("Location: event_types.php"); + exit(); +} + +http_response_code(400); +header('Content-Type: application/json'); +echo json_encode(['success' => false, 'message' => 'Invalid request.']); diff --git a/_update_function.php b/_update_function.php new file mode 100644 index 0000000..6c19bd2 --- /dev/null +++ b/_update_function.php @@ -0,0 +1,23 @@ +prepare("UPDATE functions SET name = :name, display_order = :display_order WHERE id = :id"); + $stmt->execute(['name' => $name, 'display_order' => $display_order, 'id' => $id]); + } +} + +header('Location: roles.php'); +exit(); diff --git a/_update_function_order.php b/_update_function_order.php new file mode 100644 index 0000000..f9a3434 --- /dev/null +++ b/_update_function_order.php @@ -0,0 +1,67 @@ +beginTransaction(); + + try { + foreach ($ordered_ids as $index => $id) { + $sql = "UPDATE functions SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$index + 1, $id]); + } + $pdo->commit(); + header('Content-Type: application/json'); + echo json_encode(['success' => true, 'message' => 'Order updated successfully.']); + exit(); + + } catch (PDOException $e) { + $pdo->rollBack(); + header('Content-Type: application/json'); + http_response_code(500); + echo json_encode(['success' => false, 'message' => 'Error updating display order: ' . $e->getMessage()]); + exit(); + } + } +} + +// Fallback for old form submission, though it's being deprecated +if (isset($_POST['ids']) && isset($_POST['display_order'])) { + $ids = $_POST['ids']; + $display_orders = $_POST['display_order']; + + if (count($ids) !== count($display_orders)) { + $_SESSION['error_message'] = "Something went wrong. Please try again."; + header("Location: functions.php"); + exit(); + } + + $pdo = db(); + $pdo->beginTransaction(); + + try { + for ($i = 0; $i < count($ids); $i++) { + $sql = "UPDATE functions SET display_order = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$display_orders[$i], $ids[$i]]); + } + $pdo->commit(); + $_SESSION['success_message'] = "Display order updated successfully."; + } catch (PDOException $e) { + $pdo->rollBack(); + $_SESSION['error_message'] = "Error updating display order: " . $e->getMessage(); + } + + header("Location: functions.php"); + exit(); +} + +http_response_code(400); +header('Content-Type: application/json'); +echo json_encode(['success' => false, 'message' => 'Invalid request.']); diff --git a/_update_instance_status.php b/_update_instance_status.php new file mode 100644 index 0000000..0f778ce --- /dev/null +++ b/_update_instance_status.php @@ -0,0 +1,30 @@ +prepare("UPDATE process_instances SET status = ?, lastActivityAt = NOW() WHERE id = ?"); +$stmt->execute([$status, $instanceId]); + +// Create a status change event +$stmt_event = $pdo->prepare("INSERT INTO process_events (processInstanceId, eventType, description, createdBy) VALUES (?, 'status_change', ?, ?)"); +$stmt_event->execute([$instanceId, "Status changed to $status", $userId]); + +// Redirect back to the dashboard +header("Location: process_dashboard.php"); +exit; diff --git a/_update_person.php b/_update_person.php new file mode 100644 index 0000000..833d831 --- /dev/null +++ b/_update_person.php @@ -0,0 +1,52 @@ +prepare($sql); + $stmt->execute([$firstName, $lastName, $email, $companyName, $phone, $passwordHash, $role, $personId]); + } else { + $sql = "UPDATE people SET firstName = ?, lastName = ?, email = ?, companyName = ?, phone = ?, role = ? WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$firstName, $lastName, $email, $companyName, $phone, $role, $personId]); + } + + // Update functions + $stmt = $pdo->prepare("DELETE FROM user_functions WHERE user_id = ?"); + $stmt->execute([$personId]); + + if (!empty($functions)) { + $sql = "INSERT INTO user_functions (user_id, function_id) VALUES (?, ?)"; + $stmt = $pdo->prepare($sql); + foreach ($functions as $functionId) { + $stmt->execute([$personId, $functionId]); + } + } + + $_SESSION['success_message'] = 'Osoba zaktualizowana pomyślnie.'; + + } catch (PDOException $e) { + error_log('Update failed: ' . $e->getMessage()); + $_SESSION['error_message'] = "Błąd podczas aktualizacji osoby."; + } + + header('Location: index.php'); + exit(); +} \ No newline at end of file diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..dcd26a6 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,96 @@ + +body { + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + background-color: #f8f9fa; +} + +.sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + z-index: 100; + padding: 48px 0 0; + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); + width: 250px; + transition: all 0.3s; +} + +.sidebar-collapsed { + width: 80px; +} + +.sidebar-collapsed .nav-link-text { + display: none; +} + +.sidebar-collapsed .nav-link i { + font-size: 1.5rem; + margin-right: 0; +} + + +.main-content { + margin-left: 250px; + transition: margin-left 0.3s; + padding: 20px; +} + +.main-content-collapsed { + margin-left: 80px; +} + +.nav-link { + color: #333; +} + +.nav-link.active { + color: #0d6efd; + font-weight: 500; +} + +.navbar-brand { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: 1rem; + background-color: rgba(0, 0, 0, .25); + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); +} + +.navbar .form-control { + padding: .75rem 1rem; + border-width: 0; + border-radius: 0; +} + +/* Calendar styles */ +.calendar { + table-layout: fixed; +} +.calendar td { + height: 120px; + vertical-align: top; + border: 1px solid #ddd; + padding: 4px; +} +.calendar .day-number { + font-size: 0.8rem; + font-weight: bold; + color: #333; +} +.calendar .not-month { + background-color: #f8f9fa; +} +.events { + margin-top: 4px; +} +.event { + font-size: 0.75rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.submenu-item .nav-link { + padding-left: 2.5rem; +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..3a2a7cf --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,12 @@ +document.addEventListener('DOMContentLoaded', function () { + const sidebar = document.getElementById('sidebar'); + const mainContent = document.getElementById('main-content'); + const sidebarToggler = document.getElementById('sidebar-toggler'); + + if (sidebarToggler) { + sidebarToggler.addEventListener('click', function () { + sidebar.classList.toggle('sidebar-collapsed'); + mainContent.classList.toggle('main-content-collapsed'); + }); + } +}); diff --git a/bni_groups.php b/bni_groups.php new file mode 100644 index 0000000..15477ee --- /dev/null +++ b/bni_groups.php @@ -0,0 +1,201 @@ +query("SELECT * FROM bni_groups ORDER BY display_order"); +$bni_groups = $stmt->fetchAll(PDO::FETCH_ASSOC); + +?> + +
+
+ +
+

BNI Groups

+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
NameCityActiveActions
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + diff --git a/calendar.php b/calendar.php new file mode 100644 index 0000000..b795198 --- /dev/null +++ b/calendar.php @@ -0,0 +1,303 @@ +format('t'); +$dayOfWeek = $firstDayOfMonth->format('N'); // 1 (for Monday) through 7 (for Sunday) + +// Get events for the current month +$pdo = db(); +$stmt = $pdo->prepare("SELECT c.*, t.name as type_name, t.color as type_color FROM calendar_events c LEFT JOIN event_types t ON c.event_type_id = t.id WHERE MONTH(c.start_datetime) = ? AND YEAR(c.start_datetime) = ? ORDER BY c.start_datetime ASC"); +$stmt->execute([$month, $year]); +$events = $stmt->fetchAll(PDO::FETCH_ASSOC); + +$eventsByDay = []; +foreach ($events as $event) { + $day = (new DateTime($event['start_datetime']))->format('j'); + if (!isset($eventsByDay[$day])) { + $eventsByDay[$day] = []; + } + $eventsByDay[$day][] = $event; +} + +// Get event types for the modal +$stmt_types = $pdo->query("SELECT * FROM event_types ORDER BY display_order"); +$event_types = $stmt_types->fetchAll(PDO::FETCH_ASSOC); + +$prevMonth = $month == 1 ? 12 : $month - 1; +$prevYear = $month == 1 ? $year - 1 : $year; +$nextMonth = $month == 12 ? 1 : $month + 1; +$nextYear = $month == 12 ? $year + 1 : $year; + +?> + + + +
+
+ +
+ +

format('F Y'); ?>

+
+ < Previous + Next > + +
+ + + + + + + + + + + + + + + "; + } + + $currentDay = 1; + while ($currentDay <= $daysInMonth) { + if ($dayOfWeek > 7) { + $dayOfWeek = 1; + echo ""; + } + + echo ""; + + $currentDay++; + $dayOfWeek++; + } + + // Print remaining empty cells + while ($dayOfWeek <= 7) { + echo ""; + $dayOfWeek++; + } + ?> + + +
MondayTuesdayWednesdayThursdayFridaySaturdaySunday
"; + echo "$currentDay"; + if (isset($eventsByDay[$currentDay])) { + echo "
    "; + foreach ($eventsByDay[$currentDay] as $event) { + echo '
  • ' . htmlspecialchars($event['title']) . "
  • "; + } + echo "
"; + } + echo "
+
+
+
+ + + + + + + + + + + + diff --git a/db/migrations/001_add_process_definition_json.php b/db/migrations/001_add_process_definition_json.php new file mode 100644 index 0000000..a2b7375 --- /dev/null +++ b/db/migrations/001_add_process_definition_json.php @@ -0,0 +1,8 @@ +exec($sql); + echo "Migration 001 applied: Added definition_json to process_definitions.\n"; +} + diff --git a/db/migrations/002_create_calendar_events_table.php b/db/migrations/002_create_calendar_events_table.php new file mode 100644 index 0000000..07cf954 --- /dev/null +++ b/db/migrations/002_create_calendar_events_table.php @@ -0,0 +1,17 @@ +exec($sql); + echo "Migration 002 applied: Created calendar_events table.\n"; +} + + diff --git a/db/migrations/003_create_event_types_table.php b/db/migrations/003_create_event_types_table.php new file mode 100644 index 0000000..163a56d --- /dev/null +++ b/db/migrations/003_create_event_types_table.php @@ -0,0 +1,26 @@ +exec($sql); + + // Add some default values + $sql_insert = "INSERT INTO event_types (name, color) VALUES + ('Meeting', '#007bff'), + ('Training', '#ffc107'), + ('Other', '#28a745');"; + $pdo->exec($sql_insert); + + + echo "Migration 003 completed successfully.\n"; +} catch (PDOException $e) { + die("Migration 003 failed: " . $e->getMessage() . "\n"); +} \ No newline at end of file diff --git a/db/migrations/004_add_event_type_id_to_calendar_events.php b/db/migrations/004_add_event_type_id_to_calendar_events.php new file mode 100644 index 0000000..d07992b --- /dev/null +++ b/db/migrations/004_add_event_type_id_to_calendar_events.php @@ -0,0 +1,34 @@ +exec($sql_add_column); + + // Set a default value for existing rows to avoid foreign key constraint errors + // Get the ID of the 'Other' event type + $stmt = $pdo->query("SELECT id FROM event_types WHERE name = 'Other' LIMIT 1"); + $other_type = $stmt->fetch(PDO::FETCH_ASSOC); + $default_type_id = $other_type ? $other_type['id'] : 1; // Fallback to 1 if 'Other' not found + + $sql_update_existing = "UPDATE calendar_events SET event_type_id = ? WHERE event_type_id IS NULL;"; + $stmt_update = $pdo->prepare($sql_update_existing); + $stmt_update->execute([$default_type_id]); + + // Now, add the foreign key constraint + $sql_add_fk = "ALTER TABLE calendar_events ADD CONSTRAINT fk_event_type FOREIGN KEY (event_type_id) REFERENCES event_types(id) ON DELETE SET NULL;"; + $pdo->exec($sql_add_fk); + + echo "Migration 004 completed successfully.\n"; +} catch (PDOException $e) { + // Check if the column already exists, which might happen on re-runs + if (strpos($e->getMessage(), 'Duplicate column name') !== false) { + echo "Migration 004 seems to be already applied (Column exists). Skipping.\n"; + } else { + die("Migration 004 failed: " . $e->getMessage() . "\n"); + } +} + diff --git a/db/migrations/005_create_bni_groups_table.php b/db/migrations/005_create_bni_groups_table.php new file mode 100644 index 0000000..048dec0 --- /dev/null +++ b/db/migrations/005_create_bni_groups_table.php @@ -0,0 +1,18 @@ +exec($sql); + echo "Table 'bni_groups' created successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error creating table 'bni_groups': " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/006_add_recurrence_to_calendar_events.php b/db/migrations/006_add_recurrence_to_calendar_events.php new file mode 100644 index 0000000..3f10b1c --- /dev/null +++ b/db/migrations/006_add_recurrence_to_calendar_events.php @@ -0,0 +1,20 @@ +exec($sql); + + echo "Migration 006 executed successfully: Added recurrence columns to calendar_events table.\n"; + +} catch (Exception $e) { + die("Error executing migration 006: " . $e->getMessage() . "\n"); +} \ No newline at end of file diff --git a/db/migrations/007_remove_type_from_calendar_events.php b/db/migrations/007_remove_type_from_calendar_events.php new file mode 100644 index 0000000..bf39dec --- /dev/null +++ b/db/migrations/007_remove_type_from_calendar_events.php @@ -0,0 +1,17 @@ +exec($sql); + echo "Migration 007 completed successfully: Dropped 'type' column from calendar_events.\n"; +} catch (PDOException $e) { + // Check if the column has already been dropped + if (strpos($e->getMessage(), 'column not found') !== false || strpos($e->getMessage(), 'Unknown column') !== false) { + echo "Migration 007 seems to be already applied (Column not found). Skipping.\n"; + } else { + die("Migration 007 failed: " . $e->getMessage() . "\n"); + } +} + diff --git a/db/migrations/008_create_roles_table.php b/db/migrations/008_create_roles_table.php new file mode 100644 index 0000000..8b0aa4f --- /dev/null +++ b/db/migrations/008_create_roles_table.php @@ -0,0 +1,16 @@ +exec($sql); + echo "Table 'roles' created successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error creating table 'roles': " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/009_create_user_roles_table.php b/db/migrations/009_create_user_roles_table.php new file mode 100644 index 0000000..23a269e --- /dev/null +++ b/db/migrations/009_create_user_roles_table.php @@ -0,0 +1,18 @@ +exec($sql); + echo "Table 'user_roles' created successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error creating table 'user_roles': " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/010_add_display_order_to_event_types.php b/db/migrations/010_add_display_order_to_event_types.php new file mode 100644 index 0000000..a1deab8 --- /dev/null +++ b/db/migrations/010_add_display_order_to_event_types.php @@ -0,0 +1,12 @@ +exec($sql); + echo "Migration 010_add_display_order_to_event_types executed successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error executing migration 010_add_display_order_to_event_types: " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/011_add_display_order_to_bni_groups.php b/db/migrations/011_add_display_order_to_bni_groups.php new file mode 100644 index 0000000..7fe3bde --- /dev/null +++ b/db/migrations/011_add_display_order_to_bni_groups.php @@ -0,0 +1,12 @@ +exec($sql); + echo "Migration 011_add_display_order_to_bni_groups executed successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error executing migration 011_add_display_order_to_bni_groups: " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/012_add_display_order_to_roles.php b/db/migrations/012_add_display_order_to_roles.php new file mode 100644 index 0000000..7493560 --- /dev/null +++ b/db/migrations/012_add_display_order_to_roles.php @@ -0,0 +1,12 @@ +exec($sql); + echo "Migration 012_add_display_order_to_roles executed successfully." . PHP_EOL; +} catch (PDOException $e) { + echo "Error executing migration 012_add_display_order_to_roles: " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/013_rename_roles_to_functions.php b/db/migrations/013_rename_roles_to_functions.php new file mode 100644 index 0000000..55b2e41 --- /dev/null +++ b/db/migrations/013_rename_roles_to_functions.php @@ -0,0 +1,21 @@ +exec($sql); + echo "Table 'roles' renamed to 'functions' successfully." . PHP_EOL; + + $sql = "RENAME TABLE `user_roles` TO `user_functions`;"; + $pdo->exec($sql); + echo "Table 'user_roles' renamed to 'user_functions' successfully." . PHP_EOL; + + $sql = "ALTER TABLE `user_functions` CHANGE `role_id` `function_id` INT(11) UNSIGNED NOT NULL;"; + $pdo->exec($sql); + echo "Column 'role_id' renamed to 'function_id' in 'user_functions' table successfully." . PHP_EOL; + +} catch (PDOException $e) { + echo "Error renaming tables or columns: " . $e->getMessage() . PHP_EOL; + exit(1); +} diff --git a/db/migrations/014_add_role_to_people_table.php b/db/migrations/014_add_role_to_people_table.php new file mode 100644 index 0000000..1e5d543 --- /dev/null +++ b/db/migrations/014_add_role_to_people_table.php @@ -0,0 +1,21 @@ +query("SELECT `role` FROM `people` LIMIT 1"); + } catch (PDOException $e) { + // Column does not exist, so add it + $pdo->exec("ALTER TABLE `people` ADD COLUMN `role` VARCHAR(50) NOT NULL DEFAULT 'członek' AFTER `email`"); + echo "Migration 014: Added 'role' column to 'people' table.\n"; + return; + } + + echo "Migration 014: 'role' column already exists in 'people' table. No changes made.\n"; +} + +migrate_014_add_role_to_people_table(); + diff --git a/db_setup.php b/db_setup.php new file mode 100644 index 0000000..ced3af6 --- /dev/null +++ b/db_setup.php @@ -0,0 +1,133 @@ +exec("CREATE TABLE IF NOT EXISTS `people` ( + `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + `firstName` VARCHAR(255) NOT NULL, + `lastName` VARCHAR(255) NOT NULL, + `email` VARCHAR(255) NOT NULL UNIQUE, + `password` VARCHAR(255) NULL, + `companyName` VARCHAR(255) DEFAULT NULL, + `phone` VARCHAR(50) DEFAULT NULL, + `role` ENUM('admin', 'team_member', 'member', 'guest') NOT NULL DEFAULT 'guest', + `is_user` BOOLEAN NOT NULL DEFAULT FALSE, + `active` BOOLEAN NOT NULL DEFAULT TRUE, + `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )"); + echo "People table created or already exists.\n"; + + // Seed default admin user + $stmt = $pdo->prepare("SELECT id FROM people WHERE email = ?"); + $stmt->execute(['admin@example.com']); + if ($stmt->fetchColumn() === false) { + $password = password_hash('password', PASSWORD_DEFAULT); + $insert_stmt = $pdo->prepare( + "INSERT INTO people (email, password, role, firstName, lastName, is_user, active) VALUES (?, ?, 'admin', 'Admin', 'User', TRUE, TRUE)" + ); + $insert_stmt->execute(['admin@example.com', $password]); + echo "Default admin user created. Email: admin@example.com, Password: password\n"; + } + + // 2. Process Definitions table + $pdo->exec("CREATE TABLE IF NOT EXISTS `process_definitions` ( + `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + `code` VARCHAR(255) NOT NULL UNIQUE, + `name` VARCHAR(255) NOT NULL, + `description` TEXT, + `version` INT NOT NULL DEFAULT 1, + `is_active` BOOLEAN NOT NULL DEFAULT TRUE, + `start_node_id` VARCHAR(255), + `definition_json` TEXT, + `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP + )"); + echo "Process definitions table created or already exists.\n"; + + // Seed process_definitions + $processes = [ + ['code' => 'mentoring', 'name' => 'Mentoring nowego czlonka', 'description' => 'Proces wdrozenia nowego czlonka do organizacji.'], + ['code' => 'meeting_preparation', 'name' => 'Przygotowanie spotkania grupy', 'description' => 'Proces przygotowania do spotkania grupy, w tym agenda, materialy, etc.'], + ['code' => 'guest_handling', 'name' => 'Obsluga goscia', 'description' => 'Proces obslugi gosci odwiedzajacych organizacje.'] + ]; + $stmt = $pdo->prepare("SELECT id FROM process_definitions WHERE code = ?"); + $insert_stmt = $pdo->prepare("INSERT INTO process_definitions (code, name, description) VALUES (?, ?, ?)"); + foreach ($processes as $process) { + $stmt->execute([$process['code']]); + if ($stmt->fetchColumn() === false) { + $insert_stmt->execute([$process['code'], $process['name'], $process['description']]); + echo "Seeded process: " . $process['name'] . "\n"; + } + } + + // 3. Process Instances table (updated FK) + $pdo->exec("CREATE TABLE IF NOT EXISTS `process_instances` ( + `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + `personId` INT(11) UNSIGNED NOT NULL, + `processDefinitionId` INT(11) UNSIGNED NOT NULL, + `current_status` VARCHAR(255) NOT NULL DEFAULT 'none', + `current_node_id` VARCHAR(255), + `current_reason` TEXT, + `suggested_next_step` TEXT, + `data_json` TEXT, + `lastActivityAt` TIMESTAMP NULL, + FOREIGN KEY (personId) REFERENCES people(id) ON DELETE CASCADE, + FOREIGN KEY (processDefinitionId) REFERENCES process_definitions(id) ON DELETE CASCADE, + UNIQUE KEY `person_process` (`personId`, `processDefinitionId`) + )"); + echo "Process instances table created or already exists.\n"; + + // 4. Process Events table (updated FK) + $pdo->exec("CREATE TABLE IF NOT EXISTS `process_events` ( + `id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY, + `processInstanceId` INT(11) UNSIGNED NOT NULL, + `event_type` VARCHAR(50) NOT NULL, + `message` TEXT, + `node_id` VARCHAR(255), + `payload_json` TEXT, + `createdBy` INT(11) UNSIGNED NOT NULL, + `createdAt` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (processInstanceId) REFERENCES process_instances(id) ON DELETE CASCADE, + FOREIGN KEY (createdBy) REFERENCES people(id) ON DELETE CASCADE + )"); + echo "Process events table created or already exists.\n"; + + // MIGRATIONS + echo "Starting migrations...\n"; + + // Migration: Rename `processId` to `processDefinitionId` in `process_instances` + $stmt = $pdo->query("SHOW COLUMNS FROM `process_instances` LIKE 'processId'"); + if ($stmt->fetch()) { + $checkFk = $pdo->query("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = SCHEMA() AND TABLE_NAME = 'process_instances' AND COLUMN_NAME = 'processId';")->fetch(); + if ($checkFk) { + $pdo->exec("ALTER TABLE `process_instances` DROP FOREIGN KEY `{$checkFk['CONSTRAINT_NAME']}`;"); + } + $pdo->exec("ALTER TABLE `process_instances` CHANGE `processId` `processDefinitionId` INT(11) UNSIGNED NOT NULL;"); + $pdo->exec("ALTER TABLE `process_instances` ADD FOREIGN KEY (`processDefinitionId`) REFERENCES `process_definitions`(`id`) ON DELETE CASCADE;"); + echo "Migrated process_instances: processId -> processDefinitionId.\n"; + } + + // Migration: Rename `contactId` to `personId` and update foreign key in `process_instances` + $stmt = $pdo->query("SHOW COLUMNS FROM `process_instances` LIKE 'contactId'"); + if ($stmt->fetch()) { + $checkFk = $pdo->query("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_SCHEMA = SCHEMA() AND TABLE_NAME = 'process_instances' AND COLUMN_NAME = 'contactId';")->fetch(); + if ($checkFk) { + $pdo->exec("ALTER TABLE `process_instances` DROP FOREIGN KEY `{$checkFk['CONSTRAINT_NAME']}`;"); + } + $pdo->exec("ALTER TABLE `process_instances` CHANGE `contactId` `personId` INT(11) UNSIGNED NOT NULL;"); + echo "Migrated process_instances: contactId -> personId.\n"; + } + + // Drop old tables if they exist + $pdo->exec("DROP TABLE IF EXISTS `users`, `contacts`;"); + echo "Dropped old 'users' and 'contacts' tables.\n"; + + echo "\nDatabase setup/update completed successfully.\n"; + +} catch (PDOException $e) { + die("Database setup failed: " . $e->getMessage()); +} \ No newline at end of file diff --git a/event_types.php b/event_types.php new file mode 100644 index 0000000..d5bfe74 --- /dev/null +++ b/event_types.php @@ -0,0 +1,185 @@ +query("SELECT * FROM event_types ORDER BY display_order"); +$event_types = $stmt->fetchAll(PDO::FETCH_ASSOC); + +?> + +
+
+ +
+

Event Types

+ + + + + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
NameColorActions
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/functions.php b/functions.php new file mode 100644 index 0000000..36d2c8f --- /dev/null +++ b/functions.php @@ -0,0 +1,168 @@ +query("SELECT * FROM functions ORDER BY display_order"); +$functions = $stmt->fetchAll(PDO::FETCH_ASSOC); + +?> + +
+
+ +
+

Functions

+ + +
+ + +
+ + + +
+ +
+ +
+ + + + + + + + + + + + + + + + + +
NameActions
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + diff --git a/index.php b/index.php index 7205f3d..5ae7e11 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,574 @@ getDashboardMatrix(); + +$people = $dashboardData['people']; +$processes = $dashboardData['definitions']; +$instances = $dashboardData['instances']; + +$status_colors = [ + 'none' => 'secondary', + 'negative' => 'danger', + 'in_progress' => 'warning', + 'positive' => 'success', +]; + +$pdo = db(); +$stmt_functions = $pdo->query("SELECT * FROM functions ORDER BY display_order"); +$all_functions = $stmt_functions->fetchAll(PDO::FETCH_ASSOC); + +$functions_by_id = []; +foreach ($all_functions as $function) { + $functions_by_id[$function['id']] = $function['name']; +} + +$stmt_person_functions = $pdo->query("SELECT user_id, function_id FROM user_functions"); +$person_functions_map = []; +while ($row = $stmt_person_functions->fetch(PDO::FETCH_ASSOC)) { + $person_functions_map[$row['user_id']][] = $row['function_id']; +} -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); ?> - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ + + +
+
+ + +
+ + + + + + + + + + + + +
+

Process Dashboard

+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + +
Person
+
+ +
+ +
+ +
+ + + +
+
+ +
+
+   + +
+
+
-
- - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..92f1c5f --- /dev/null +++ b/login.php @@ -0,0 +1,80 @@ +prepare("SELECT * FROM people WHERE email = ? AND is_user = TRUE AND active = TRUE"); + $stmt->execute([$email]); + $person = $stmt->fetch(); + + if ($person && password_verify($password, $person['password'])) { + $_SESSION['user_id'] = $person['id']; + $_SESSION['user_email'] = $person['email']; + $_SESSION['user_role'] = $person['role']; + $_SESSION['user_name'] = $person['firstName'] . ' ' . $person['lastName']; + header('Location: index.php'); + exit; + } else { + $error = 'Nieprawidłowe dane logowania. Spróbuj ponownie.'; + } + } catch (PDOException $e) { + $error = 'Błąd bazy danych: ' . $e->getMessage(); + } + } +} +?> + + + + + + Logowanie + + + + +
+
+

Logowanie do systemu

+ +
+ +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ + diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..95db42c --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ +exec("CREATE TABLE IF NOT EXISTS migrations (id INT AUTO_INCREMENT PRIMARY KEY, migration VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"); + + // Get all run migrations + $stmt = $pdo->query("SELECT migration FROM migrations"); + $run_migrations = $stmt->fetchAll(PDO::FETCH_COLUMN); + + // Get all migration files + $migration_files = glob('db/migrations/*.php'); + + foreach ($migration_files as $file) { + $migration_name = basename($file, '.php'); + + if (!in_array($migration_name, $run_migrations)) { + echo "Running migration: $migration_name...\n"; + require_once $file; + + try { + // Migration functions are named like migrate_001, migrate_002 etc. + $function_name = 'migrate_' . preg_replace('/[^0-9]/', '', $migration_name); + if(function_exists($function_name)){ + $function_name($pdo); + } else { + // Fallback for older naming convention + $function_name = str_replace('.php', '', basename($file)); + if(function_exists($function_name)) { + $function_name($pdo); + } + } + + // Record migration + $stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?)"); + $stmt->execute([$migration_name]); + echo "Migration $migration_name has been applied.\n"; + } catch (PDOException $e) { + echo "Error running migration $migration_name: " . $e->getMessage() . "\n"; + } + } else { + echo "Migration $migration_name already applied.\n"; + } + } + + echo "All migrations have been run.\n"; + + } catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); + } +} + +// If the script is run directly from the command line +if (php_sapi_name() === 'cli') { + run_migrations(); +} + + diff --git a/process_definitions.php b/process_definitions.php new file mode 100644 index 0000000..ef1b232 --- /dev/null +++ b/process_definitions.php @@ -0,0 +1,158 @@ +query("SELECT * FROM process_definitions ORDER BY name"); +$processes = $stmt->fetchAll(PDO::FETCH_ASSOC); + +?> + + + +
+
+ + +
+
+

Process Definitions

+
+ +
+
+ +
+ + + + + + + + + + + + + + + +
NameActions
+ + +
+
+
+
+
+ + + + + + + diff --git a/test.php b/test.php new file mode 100644 index 0000000..61ace19 --- /dev/null +++ b/test.php @@ -0,0 +1,2 @@ +"; + +if (!isset($_SESSION['user_id'])) { + echo "user_id not set.
"; + // header('Location: login.php'); + // exit; +} + +echo "end of test"; +?>