Poprawki po aktualizacji

This commit is contained in:
Flatlogic Bot 2026-03-02 17:03:42 +00:00
parent 9ea7b9d268
commit 2e85c01115
7 changed files with 350 additions and 65 deletions

View File

@ -183,7 +183,8 @@ $spotkania_cols = [];
$spotkania_cols[$meeting['group_id']]['group_name'] = $meeting['group_name']; $spotkania_cols[$meeting['group_id']]['group_name'] = $meeting['group_name'];
$spotkania_cols[$meeting['group_id']]['meetings'][] = [ $spotkania_cols[$meeting['group_id']]['meetings'][] = [
'datetime' => $meeting['start_datetime'], 'datetime' => $meeting['start_datetime'],
'meeting_id' => $meetingId 'meeting_id' => $meetingId,
'cycle_key' => $meeting['group_id'] . '_' . $meeting['start_datetime']
]; ];
} }
@ -1005,6 +1006,7 @@ $spotkania_cols = [];
$isMember = $this->isMemberOfGroup($personId, $bniGroupId); $isMember = $this->isMemberOfGroup($personId, $bniGroupId);
return [ return [
'meeting_id' => $meetingId, 'meeting_id' => $meetingId,
'cycle_key' => $meeting['group_id'] . '_' . $meeting['start_datetime'],
'person_id' => $personId, 'person_id' => $personId,
'attendance_status' => $isMember ? 'present' : 'none', 'attendance_status' => $isMember ? 'present' : 'none',
'guest_survey' => null, 'guest_survey' => null,

View File

@ -14,6 +14,9 @@ if (!isset($_SESSION['user_id'])) {
} }
$person_id = $_GET['person_id'] ?? null; $person_id = $_GET['person_id'] ?? null;
$subject_id = $_GET['subject_id'] ?? $person_id;
$subject_type = $_GET['subject_type'] ?? 'person';
$cycle_key = $_GET['cycle_key'] ?? null;
$process_definition_id = $_GET['process_id'] ?? null; $process_definition_id = $_GET['process_id'] ?? null;
$process_code = $_GET['process_code'] ?? null; $process_code = $_GET['process_code'] ?? null;
@ -63,7 +66,7 @@ if (!$process) {
} }
// Try to find an existing instance // Try to find an existing instance
$instance = $engine->getActiveInstanceForSubject($process['code'], $subject_type, $subject_id); $instance = $engine->getActiveInstanceForSubject($process['code'], $subject_type, $subject_id, $cycle_key);
?> ?>
@ -289,7 +292,7 @@ $instance = $engine->getActiveInstanceForSubject($process['code'], $subject_type
<?php if ($eligibility['is_eligible']): ?> <?php if ($eligibility['is_eligible']): ?>
<h4><?= t('modal.process_not_started', 'Proces nie został uruchomiony') ?></h4> <h4><?= t('modal.process_not_started', 'Proces nie został uruchomiony') ?></h4>
<p>This process has not been started for this person.</p> <p>This process has not been started for this person.</p>
<button id="startProcessBtn" class="btn btn-primary" data-subject-type="<?= $subject_type ?>" data-subject-id="<?= $subject_id ?>" data-person-id="<?= $person_id ?>" data-process-id="<?= $process_definition_id ?>"> <button id="startProcessBtn" class="btn btn-primary" data-subject-type="<?= $subject_type ?>" data-subject-id="<?= $subject_id ?>" data-process-id="<?= $process_definition_id ?>" data-process-code="<?= $process_code ?>" data-cycle-key="<?= $cycle_key ?>">
<?= t('modal.start_process', 'Uruchom proces') ?> <?= t('modal.start_process', 'Uruchom proces') ?>
</button> </button>
<?php else: ?> <?php else: ?>

View File

@ -46,7 +46,7 @@ $engine = new WorkflowEngine();
$code = $stmt_def->fetchColumn() ?: $processCode; $code = $stmt_def->fetchColumn() ?: $processCode;
if($deleteExisting === '1') { if($deleteExisting === '1') {
$instance = $engine->getActiveInstanceForSubject($code, $subjectType, $subjectId); $instance = $engine->getActiveInstanceForSubject($code, $subjectType, $subjectId, $cycleKey);
if ($instance) { if ($instance) {
$engine->deleteInstance($instance['id']); $engine->deleteInstance($instance['id']);
} }
@ -54,7 +54,7 @@ if($deleteExisting === '1') {
if ($mode === 'create_new_run' || filter_input(INPUT_POST, 'force', FILTER_VALIDATE_INT) === 1) { if ($mode === 'create_new_run' || filter_input(INPUT_POST, 'force', FILTER_VALIDATE_INT) === 1) {
// start new process // start new process
$instanceId = $engine->startProcessForSubject($code, $subjectType, $subjectId, $userId, 'create_new_run'); $instanceId = $engine->startProcessForSubject($code, $subjectType, $subjectId, $userId, 'create_new_run', $cycleKey);
$stmt = $pdo->prepare("SELECT * FROM process_instances WHERE id = ?"); $stmt = $pdo->prepare("SELECT * FROM process_instances WHERE id = ?");
$stmt->execute([$instanceId]); $stmt->execute([$instanceId]);
$instance = $stmt->fetch(PDO::FETCH_ASSOC); $instance = $stmt->fetch(PDO::FETCH_ASSOC);

175
index.php
View File

@ -266,7 +266,7 @@ foreach ($definitions as $def) {
$color = $status_colors[$status] ?? 'secondary'; $color = $status_colors[$status] ?? 'secondary';
$lastActivity = $instance && $instance['last_activity_at'] ? date('d/m/y', strtotime($instance['last_activity_at'])) : ''; $lastActivity = $instance && $instance['last_activity_at'] ? date('d/m/y', strtotime($instance['last_activity_at'])) : '';
?> ?>
<td class="text-center align-middle" data-bs-toggle="modal" data-bs-target="#instanceModal" data-person-id="<?= $person['id'] ?>" data-process-id="<?= $process['id'] ?>"> <td class="text-center align-middle" data-bs-toggle="modal" data-bs-target="#instanceModal" data-subject-type="person" data-subject-id="<?= $person['id'] ?>" data-person-id="<?= $person['id'] ?>" data-process-id="<?= $process['id'] ?>">
<span class="badge rounded-circle bg-<?= $color ?>" style="width: 20px; height: 20px; display: inline-block;" title="<?= ucfirst($status) ?>">&nbsp;</span> <span class="badge rounded-circle bg-<?= $color ?>" style="width: 20px; height: 20px; display: inline-block;" title="<?= ucfirst($status) ?>">&nbsp;</span>
<small class="text-muted d-block"><?= $lastActivity ?></small> <small class="text-muted d-block"><?= $lastActivity ?></small>
</td> </td>
@ -717,7 +717,7 @@ foreach ($definitions as $def) {
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
const meetingProcesses = <?= json_encode($meeting_processes ?? []) ?>; const meetingProcesses = <?= json_encode($meeting_processes ?? []) ?>;
const statusColors = <?= json_encode($status_colors ?? []) ?>; if (!window.STATUS_COLORS) { window.STATUS_COLORS = <?= json_encode($status_colors ?? []) ?>; }
const meetingModal = new bootstrap.Modal(document.getElementById('meetingAttendanceModal')); const meetingModal = new bootstrap.Modal(document.getElementById('meetingAttendanceModal'));
@ -728,15 +728,16 @@ document.addEventListener('DOMContentLoaded', function () {
const meetingDateInput = document.getElementById('meetingDate'); const meetingDateInput = document.getElementById('meetingDate');
const attendanceStatus = document.getElementById('attendanceStatus'); const attendanceStatus = document.getElementById('attendanceStatus');
const guestSurveySection = document.getElementById('guestSurveySection'); const guestSurveySection = document.getElementById('guestSurveySection');
const statusColors = { if (!window.STATUS_COLORS) window.STATUS_COLORS = {};
Object.assign(window.STATUS_COLORS, {
'none': 'secondary', 'none': 'secondary',
'absent': 'danger', 'absent': 'danger',
'substitute': 'warning', 'substitute': 'warning',
'present': 'success', 'present': 'success',
}; });
function updateDot(dot, status) { function updateDot(dot, status) {
const color = statusColors[status] || 'secondary'; const color = window.STATUS_COLORS[status] || 'secondary';
dot.className = `badge rounded-circle bg-${color} meeting-dot`; dot.className = `badge rounded-circle bg-${color} meeting-dot`;
dot.dataset.currentStatus = status; dot.dataset.currentStatus = status;
dot.title = `Status: ${status.charAt(0).toUpperCase() + status.slice(1)}`; dot.title = `Status: ${status.charAt(0).toUpperCase() + status.slice(1)}`;
@ -886,6 +887,7 @@ document.addEventListener('DOMContentLoaded', function () {
const currentMeetingObj = meetings[currentIndex]; const currentMeetingObj = meetings[currentIndex];
const currentMeetingDate = typeof currentMeetingObj === 'object' ? currentMeetingObj.datetime : currentMeetingObj; const currentMeetingDate = typeof currentMeetingObj === 'object' ? currentMeetingObj.datetime : currentMeetingObj;
const currentMeetingId = typeof currentMeetingObj === 'object' ? currentMeetingObj.meeting_id : null; const currentMeetingId = typeof currentMeetingObj === 'object' ? currentMeetingObj.meeting_id : null;
const currentCycleKey = typeof currentMeetingObj === 'object' ? currentMeetingObj.cycle_key : null;
headerCell.querySelector('.meeting-date').textContent = new Date(currentMeetingDate).toLocaleDateString('pl-PL', { day: '2-digit', month: '2-digit', year: 'numeric' }); headerCell.querySelector('.meeting-date').textContent = new Date(currentMeetingDate).toLocaleDateString('pl-PL', { day: '2-digit', month: '2-digit', year: 'numeric' });
const processContainer = headerCell.querySelector('.meeting-process-container'); const processContainer = headerCell.querySelector('.meeting-process-container');
@ -894,9 +896,12 @@ document.addEventListener('DOMContentLoaded', function () {
const dot = processContainer.querySelector('.meeting-process-dot'); const dot = processContainer.querySelector('.meeting-process-dot');
if (dot) { if (dot) {
dot.dataset.subjectId = currentMeetingId; dot.dataset.subjectId = currentMeetingId;
dot.dataset.cycleKey = currentCycleKey;
dot.dataset.processCode = 'meeting_preparation';
dot.dataset.subjectType = 'meeting';
const instance = meetingProcesses[currentMeetingId] && meetingProcesses[currentMeetingId]['meeting_preparation']; const instance = meetingProcesses[currentMeetingId] && meetingProcesses[currentMeetingId]['meeting_preparation'];
const status = instance ? instance.computed_status : 'none'; const status = instance ? instance.computed_status : 'none';
const color = statusColors[status] || 'secondary'; const color = window.STATUS_COLORS[status] || 'secondary';
dot.className = `badge rounded-circle bg-${color} process-dot meeting-process-dot`; dot.className = `badge rounded-circle bg-${color} process-dot meeting-process-dot`;
dot.dataset.processId = instance ? instance.id : ''; dot.dataset.processId = instance ? instance.id : '';
} }
@ -967,17 +972,78 @@ document.addEventListener('DOMContentLoaded', function () {
var instanceModal = document.getElementById('instanceModal'); var instanceModal = document.getElementById('instanceModal');
instanceModal.addEventListener('show.bs.modal', function (event) { instanceModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget; var button = event.relatedTarget;
var personId = button.dataset.personId || ''; if (!button) return;
var processId = button.dataset.processId;
var subjectType = button.dataset.subjectType || 'person'; var subjectType = button.dataset.subjectType || 'person';
var subjectId = button.dataset.subjectId || personId; var subjectId = button.dataset.subjectId || button.dataset.personId || '';
var personId = button.dataset.personId || '';
var processId = button.dataset.processId || '';
var processCode = button.dataset.processCode || '';
var cycleKey = button.dataset.cycleKey || '';
instanceModal.dataset.lastSubjectType = subjectType;
instanceModal.dataset.lastSubjectId = subjectId;
instanceModal.dataset.lastPersonId = personId;
instanceModal.dataset.lastProcessId = processId;
instanceModal.dataset.lastProcessCode = processCode;
instanceModal.dataset.lastCycleKey = cycleKey;
var modalTitle = instanceModal.querySelector('.modal-title');
var modalBody = instanceModal.querySelector('.modal-body'); var modalBody = instanceModal.querySelector('.modal-body');
// Load content via AJAX modalTitle.textContent = 'Ładowanie...';
fetch(`_get_instance_details.php?person_id=${personId}&subject_type=${subjectType}&subject_id=${subjectId}&process_id=${processId}`) modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ladowanie...</p></div>';
.then(response => response.text())
.then(html => { if (!subjectId) {
modalTitle.textContent = 'Błąd parametru';
modalBody.innerHTML = '<div class="alert alert-danger m-3">Brak wymaganego identyfikatora (subject_id). Nie można załadować procesu.</div>';
return;
}
if (!processId && !processCode) {
modalTitle.textContent = 'Błąd parametru';
modalBody.innerHTML = '<div class="alert alert-danger m-3">Brak identyfikatora procesu (process_id lub process_code). Nie można załadować procesu.</div>';
return;
}
var url = '_get_instance_details.php?subject_type=' + encodeURIComponent(subjectType) + '&subject_id=' + encodeURIComponent(subjectId);
if (personId) url += '&person_id=' + encodeURIComponent(personId);
if (processId) url += '&process_id=' + encodeURIComponent(processId);
if (processCode) url += '&process_code=' + encodeURIComponent(processCode);
if (cycleKey) url += '&cycle_key=' + encodeURIComponent(cycleKey);
fetch(url)
.then(function(response) {
if (!response.ok) {
return response.text().then(function(text) {
var errStr = 'HTTP ' + response.status + ': ';
var corrId = '';
try {
var data = JSON.parse(text);
errStr += (data.error && data.error.message) ? data.error.message : (data.error || text);
if (data.correlation_id) corrId = data.correlation_id;
} catch (e) {
errStr += text.substring(0, 100);
}
throw new Error(errStr + (corrId ? ' (ID: ' + corrId + ')' : ''));
});
}
return response.text();
})
.then(function(html) {
modalBody.innerHTML = html; modalBody.innerHTML = html;
var returnedTitle = modalBody.querySelector('#instance-modal-title');
if (returnedTitle) {
modalTitle.innerHTML = returnedTitle.innerHTML;
returnedTitle.remove();
} else {
modalTitle.textContent = 'Szczegóły Procesu';
}
})
.catch(function(err) {
console.error('Fetch error:', err);
modalTitle.textContent = 'Błąd';
modalBody.innerHTML = '<div class="alert alert-danger m-3"><strong>Błąd ładowania:</strong><br>' + err.message + '</div>';
}); });
}); });
@ -1239,11 +1305,14 @@ document.addEventListener('DOMContentLoaded', function () {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
const personId = btn.dataset.personId; const subjectType = btn.dataset.subjectType || 'person';
const subjectId = btn.dataset.subjectId || btn.dataset.personId;
const processId = btn.dataset.processId; const processId = btn.dataset.processId;
const processCode = btn.dataset.processCode;
const cycleKey = btn.dataset.cycleKey;
if (!personId || !processId) { if (!subjectId || (!processId && !processCode)) {
alert('Brak ID osoby lub procesu'); alert('Brak wymaganych parametrów do uruchomienia procesu.');
return; return;
} }
@ -1252,11 +1321,18 @@ document.addEventListener('DOMContentLoaded', function () {
btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Uruchamianie...'; btn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Uruchamianie...';
const formData = new FormData(); const formData = new FormData();
formData.append('person_id', personId); formData.append('subject_type', subjectType);
formData.append('process_id', processId); formData.append('subject_id', subjectId);
if (processId) formData.append('process_id', processId);
if (processCode) formData.append('process_code', processCode);
if (cycleKey) formData.append('cycle_key', cycleKey);
if (instanceModalElement) { if (instanceModalElement) {
instanceModalElement.dataset.lastPersonId = personId; instanceModalElement.dataset.lastSubjectType = subjectType;
instanceModalElement.dataset.lastSubjectId = subjectId;
instanceModalElement.dataset.lastProcessId = processId; instanceModalElement.dataset.lastProcessId = processId;
instanceModalElement.dataset.lastProcessCode = processCode;
instanceModalElement.dataset.lastCycleKey = cycleKey;
} }
fetch('_init_single_instance.php', { fetch('_init_single_instance.php', {
@ -1269,7 +1345,12 @@ document.addEventListener('DOMContentLoaded', function () {
const modalBody = instanceModalElement.querySelector('.modal-body'); const modalBody = instanceModalElement.querySelector('.modal-body');
modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ładowanie...</p></div>'; modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ładowanie...</p></div>';
fetch(`_get_instance_details.php?person_id=${personId}&process_id=${processId}`) let url = `_get_instance_details.php?subject_type=${encodeURIComponent(subjectType)}&subject_id=${encodeURIComponent(subjectId)}`;
if (processId) url += `&process_id=${encodeURIComponent(processId)}`;
if (processCode) url += `&process_code=${encodeURIComponent(processCode)}`;
if (cycleKey) url += `&cycle_key=${encodeURIComponent(cycleKey)}`;
fetch(url)
.then(r => r.text()) .then(r => r.text())
.then(html => { .then(html => {
modalBody.innerHTML = html; modalBody.innerHTML = html;
@ -1296,12 +1377,15 @@ document.addEventListener('DOMContentLoaded', function () {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
const personId = restartBtn.dataset.personId; const subjectType = restartBtn.dataset.subjectType || 'person';
const subjectId = restartBtn.dataset.subjectId || restartBtn.dataset.personId;
const processCode = restartBtn.dataset.processCode; const processCode = restartBtn.dataset.processCode;
const processId = restartBtn.dataset.processId;
const cycleKey = restartBtn.dataset.cycleKey;
const mode = restartBtn.dataset.mode; const mode = restartBtn.dataset.mode;
if (!personId || !processCode) { if (!subjectId || !processCode) {
alert('Brak ID osoby lub kodu procesu'); alert('Brak wymaganych parametrów do zrestartowania procesu.');
return; return;
} }
@ -1310,8 +1394,11 @@ document.addEventListener('DOMContentLoaded', function () {
restartBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>...'; restartBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>...';
const formData = new FormData(); const formData = new FormData();
formData.append('person_id', personId); formData.append('subject_type', subjectType);
formData.append('subject_id', subjectId);
formData.append('process_code', processCode); formData.append('process_code', processCode);
if (processId) formData.append('process_id', processId);
if (cycleKey) formData.append('cycle_key', cycleKey);
formData.append('mode', mode || 'create_new_run'); formData.append('mode', mode || 'create_new_run');
fetch('_init_single_instance.php', { fetch('_init_single_instance.php', {
@ -1332,10 +1419,8 @@ document.addEventListener('DOMContentLoaded', function () {
const modalBody = instanceModalElement.querySelector('.modal-body'); const modalBody = instanceModalElement.querySelector('.modal-body');
modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ładowanie...</p></div>'; modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ładowanie...</p></div>';
// Use process_id if we have it from dataset, otherwise fetch using code. let fetchUrl = `_get_instance_details.php?subject_type=${encodeURIComponent(subjectType)}&subject_id=${encodeURIComponent(subjectId)}&process_code=${encodeURIComponent(processCode)}`;
// The original _get_instance_details endpoint seems to accept process_id or process_code? Let's check. if (cycleKey) fetchUrl += `&cycle_key=${encodeURIComponent(cycleKey)}`;
// Actually let's use the instanceModalElement.dataset.lastProcessId if it exists.
const fetchUrl = `_get_instance_details.php?person_id=${personId}&process_code=${processCode}`;
fetch(fetchUrl) fetch(fetchUrl)
.then(r => r.text()) .then(r => r.text())
@ -1393,10 +1478,18 @@ document.addEventListener('DOMContentLoaded', function () {
.then(data => { .then(data => {
if (data.success || !data.error) { if (data.success || !data.error) {
// Reload modal content // Reload modal content
const personId = instanceModalElement.dataset.lastPersonId; const subjectType = instanceModalElement.dataset.lastSubjectType || 'person';
const subjectId = instanceModalElement.dataset.lastSubjectId;
const processId = instanceModalElement.dataset.lastProcessId; const processId = instanceModalElement.dataset.lastProcessId;
const processCode = instanceModalElement.dataset.lastProcessCode;
const cycleKey = instanceModalElement.dataset.lastCycleKey;
fetch(`_get_instance_details.php?person_id=${personId}&process_id=${processId}`) let url = `_get_instance_details.php?subject_type=${encodeURIComponent(subjectType)}&subject_id=${encodeURIComponent(subjectId)}`;
if (processId) url += `&process_id=${encodeURIComponent(processId)}`;
if (processCode) url += `&process_code=${encodeURIComponent(processCode)}`;
if (cycleKey) url += `&cycle_key=${encodeURIComponent(cycleKey)}`;
fetch(url)
.then(r => r.text()) .then(r => r.text())
.then(html => { .then(html => {
instanceModalElement.querySelector('.modal-body').innerHTML = html; instanceModalElement.querySelector('.modal-body').innerHTML = html;
@ -1443,10 +1536,18 @@ document.addEventListener('DOMContentLoaded', function () {
.then(r => r.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.success || !data.error) { if (data.success || !data.error) {
const personId = instanceModalElement.dataset.lastPersonId; const subjectType = instanceModalElement.dataset.lastSubjectType || 'person';
const subjectId = instanceModalElement.dataset.lastSubjectId;
const processId = instanceModalElement.dataset.lastProcessId; const processId = instanceModalElement.dataset.lastProcessId;
const processCode = instanceModalElement.dataset.lastProcessCode;
const cycleKey = instanceModalElement.dataset.lastCycleKey;
fetch(`_get_instance_details.php?person_id=${personId}&process_id=${processId}`) let url = `_get_instance_details.php?subject_type=${encodeURIComponent(subjectType)}&subject_id=${encodeURIComponent(subjectId)}`;
if (processId) url += `&process_id=${encodeURIComponent(processId)}`;
if (processCode) url += `&process_code=${encodeURIComponent(processCode)}`;
if (cycleKey) url += `&cycle_key=${encodeURIComponent(cycleKey)}`;
fetch(url)
.then(r => r.text()) .then(r => r.text())
.then(html => { .then(html => {
instanceModalElement.querySelector('.modal-body').innerHTML = html; instanceModalElement.querySelector('.modal-body').innerHTML = html;
@ -1499,16 +1600,6 @@ document.addEventListener('DOMContentLoaded', function () {
} }
}); });
// Save personId and processId on modal show so we can use it to reload later
instanceModalElement.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
if(button && button.dataset) {
if (button.dataset.personId) instanceModalElement.dataset.lastPersonId = button.dataset.personId;
if (button.dataset.processId) instanceModalElement.dataset.lastProcessId = button.dataset.processId;
if (button.dataset.subjectType) instanceModalElement.dataset.lastSubjectType = button.dataset.subjectType;
if (button.dataset.subjectId) instanceModalElement.dataset.lastSubjectId = button.dataset.subjectId;
}
});
} }
instanceModalElement.addEventListener('hidden.bs.modal', function () { instanceModalElement.addEventListener('hidden.bs.modal', function () {

View File

@ -1,17 +0,0 @@
import re
with open('WorkflowEngine.php', 'r') as f:
content = f.read()
target = """ $stmt = $this->pdo->prepare("SELECT * FROM process_instances WHERE `person_id` = ? AND `process_definition_id` = ?");
$stmt->execute([$personId, $processDefinitionId]);
$instance = $stmt->fetch(PDO::FETCH_ASSOC);"""
replacement = """ $instance = $this->getInstanceByDefId($personId, $processDefinitionId);"""
content = content.replace(target, replacement)
with open('WorkflowEngine.php', 'w') as f:
f.write(content)
print("Patched.")

38
patch_index3.py Normal file
View File

@ -0,0 +1,38 @@
import re
with open('index.php', 'r', encoding='utf-8') as f:
content = f.read()
# 1. Update Inne Procesy dots
content = re.sub(
r'<td class="text-center align-middle" data-bs-toggle="modal" data-bs-target="#instanceModal" data-person-id="<\?= \$person[\'id\'] \?>" data-process-id="<\?= \$process[\'id\'] \?>(.*?)">',
r'<td class="text-center align-middle" data-bs-toggle="modal" data-bs-target="#instanceModal" data-subject-type="person" data-subject-id="<?= $person[\'id\'] ?>" data-process-id="<?= $process[\'id\'] ?>"\1> ',
content,
flags=re.DOTALL
)
# 2. Update meeting dots initial HTML
content = re.sub(
r'data-process-id="<\?= \$mp_def[\'id\'] \?>"\s*data-subject-type="meeting"\s*data-subject-id=""',
r'data-process-id="<?= $mp_def[\'id\'] ?>" data-process-code="meeting_preparation" data-subject-type="meeting" data-subject-id="" data-cycle-key=""',
content
)
# 3. Update updateMeetingView JS function
# Find currentMeetingId assignment
content = re.sub(
r"const currentMeetingId = typeof currentMeetingObj === 'object' \? currentMeetingObj.meeting_id : null;",
r"const currentMeetingId = typeof currentMeetingObj === 'object' ? currentMeetingObj.meeting_id : null;\n const currentCycleKey = typeof currentMeetingObj === 'object' ? currentMeetingObj.cycle_key : null;",
content
)
# Find dot.dataset.subjectId = currentMeetingId;
content = re.sub(
r'dot.dataset.subjectId = currentMeetingId;',
r"dot.dataset.subjectId = currentMeetingId;\n dot.dataset.cycleKey = currentCycleKey;\n dot.dataset.processCode = 'meeting_preparation';\n dot.dataset.subjectType = 'meeting';",
content
)
with open('index.php', 'w', encoding='utf-8') as f:
f.write(content)
print("index.php patched (step 1-3)")

168
patch_index4.py Normal file
View File

@ -0,0 +1,168 @@
import re
with open('index.php', 'r', encoding='utf-8') as f:
content = f.read()
# Replace the handler
old_handler = """ var instanceModal = document.getElementById('instanceModal');
instanceModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
if (!button) return;
var personId = button.dataset.personId || '';
var processId = button.dataset.processId || '';
var processCode = button.dataset.processCode || '';
var subjectType = button.dataset.subjectType || 'person';
var subjectId = button.dataset.subjectId || personId;
var cycleKey = button.dataset.cycleKey || '';
instanceModal.dataset.lastPersonId = personId;
instanceModal.dataset.lastProcessId = processId;
instanceModal.dataset.lastProcessCode = processCode;
instanceModal.dataset.lastSubjectType = subjectType;
instanceModal.dataset.lastSubjectId = subjectId;
instanceModal.dataset.lastCycleKey = cycleKey;
var modalBody = instanceModal.querySelector('.modal-body');
modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ladowanie...</p></div>';
var url = '_get_instance_details.php?subject_type=' + encodeURIComponent(subjectType) + '&subject_id=' + encodeURIComponent(subjectId);
if (personId) url += '&person_id=' + encodeURIComponent(personId);
if (processId) url += '&process_id=' + encodeURIComponent(processId);
if (processCode) url += '&process_code=' + encodeURIComponent(processCode);
if (cycleKey) url += '&cycle_key=' + encodeURIComponent(cycleKey);
fetch(url)
.then(function(response) {
if (!response.ok) {
return response.text().then(function(text) {
var errStr = 'HTTP ' + response.status + ': ';
var corrId = '';
try {
var data = JSON.parse(text);
errStr += (data.error && data.error.message) ? data.error.message : (data.error || text);
if (data.correlation_id) corrId = data.correlation_id;
} catch (e) {
errStr += text.substring(0, 100);
}
throw new Error(errStr + (corrId ? ' (ID: ' + corrId + ')' : ''));
});
}
return response.text();
})
.then(function(html) {
modalBody.innerHTML = html;
var returnedTitle = modalBody.querySelector('#instance-modal-title');
if (returnedTitle) {
var modalTitleElem = instanceModal.querySelector('.modal-title');
if (modalTitleElem) {
modalTitleElem.innerHTML = returnedTitle.innerHTML;
returnedTitle.remove();
}
}
})
.catch(function(err) {
console.error('Fetch error:', err);
modalBody.innerHTML = '<div class="alert alert-danger m-3"><strong>Błąd ładowania:</strong><br>' + err.message + '</div>';
});
});"""
new_handler = """ var instanceModal = document.getElementById('instanceModal');
instanceModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
if (!button) return;
var subjectType = button.dataset.subjectType || 'person';
var subjectId = button.dataset.subjectId || button.dataset.personId || '';
var personId = button.dataset.personId || '';
var processId = button.dataset.processId || '';
var processCode = button.dataset.processCode || '';
var cycleKey = button.dataset.cycleKey || '';
instanceModal.dataset.lastSubjectType = subjectType;
instanceModal.dataset.lastSubjectId = subjectId;
instanceModal.dataset.lastPersonId = personId;
instanceModal.dataset.lastProcessId = processId;
instanceModal.dataset.lastProcessCode = processCode;
instanceModal.dataset.lastCycleKey = cycleKey;
var modalTitle = instanceModal.querySelector('.modal-title');
var modalBody = instanceModal.querySelector('.modal-body');
modalTitle.textContent = 'Ładowanie...';
modalBody.innerHTML = '<div class="text-center mt-4"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">Ladowanie...</p></div>';
if (!subjectId) {
modalTitle.textContent = 'Błąd parametru';
modalBody.innerHTML = '<div class="alert alert-danger m-3">Brak wymaganego identyfikatora (subject_id). Nie można załadować procesu.</div>';
return;
}
if (!processId && !processCode) {
modalTitle.textContent = 'Błąd parametru';
modalBody.innerHTML = '<div class="alert alert-danger m-3">Brak identyfikatora procesu (process_id lub process_code). Nie można załadować procesu.</div>';
return;
}
var url = '_get_instance_details.php?subject_type=' + encodeURIComponent(subjectType) + '&subject_id=' + encodeURIComponent(subjectId);
if (personId) url += '&person_id=' + encodeURIComponent(personId);
if (processId) url += '&process_id=' + encodeURIComponent(processId);
if (processCode) url += '&process_code=' + encodeURIComponent(processCode);
if (cycleKey) url += '&cycle_key=' + encodeURIComponent(cycleKey);
fetch(url)
.then(function(response) {
if (!response.ok) {
return response.text().then(function(text) {
var errStr = 'HTTP ' + response.status + ': ';
var corrId = '';
try {
var data = JSON.parse(text);
errStr += (data.error && data.error.message) ? data.error.message : (data.error || text);
if (data.correlation_id) corrId = data.correlation_id;
} catch (e) {
errStr += text.substring(0, 100);
}
throw new Error(errStr + (corrId ? ' (ID: ' + corrId + ')' : ''));
});
}
return response.text();
})
.then(function(html) {
modalBody.innerHTML = html;
var returnedTitle = modalBody.querySelector('#instance-modal-title');
if (returnedTitle) {
modalTitle.innerHTML = returnedTitle.innerHTML;
returnedTitle.remove();
} else {
modalTitle.textContent = 'Szczegóły Procesu';
}
})
.catch(function(err) {
console.error('Fetch error:', err);
modalTitle.textContent = 'Błąd';
modalBody.innerHTML = '<div class="alert alert-danger m-3"><strong>Błąd ładowania:</strong><br>' + err.message + '</div>';
});
});"""
if old_handler in content:
content = content.replace(old_handler, new_handler)
else:
print("Could not find the old handler exactly as written. Applying regex replacement instead.")
# More robust replacement
start_str = "var instanceModal = document.getElementById('instanceModal');\n instanceModal.addEventListener('show.bs.modal', function (event) {"
start_idx = content.find(start_str)
if start_idx != -1:
end_idx = content.find("});", start_idx) + 3
# Look for the next section to make sure we got the right block
next_section = content.find(" // Bulk actions", end_idx)
if next_section != -1 and next_section - end_idx < 100:
content = content[:start_idx] + new_handler + content[end_idx:]
else:
print("Found start but next section is too far. Replacing block anyway.")
content = content[:start_idx] + new_handler + content[end_idx:]
with open('index.php', 'w', encoding='utf-8') as f:
f.write(content)
print("index.php patched (step 4)")