328 lines
13 KiB
PHP
328 lines
13 KiB
PHP
<?php
|
|
|
|
class ADBNetzgebietController extends mfBaseController {
|
|
|
|
public User $me;
|
|
private array $postData = [];
|
|
|
|
protected function init(): void {
|
|
$this->needlogin = true;
|
|
$this->me = new User();
|
|
$this->me->loadMe();
|
|
$this->layout()->set("me", $this->me);
|
|
|
|
if (!$this->me->is("Admin")) {
|
|
$this->redirect("Dashboard");
|
|
}
|
|
|
|
$rawInput = file_get_contents('php://input');
|
|
if ($rawInput) $this->postData = json_decode($rawInput, true) ?? [];
|
|
}
|
|
|
|
protected function indexAction(): void {
|
|
Helper::renderVue3($this, $this->mod, "Netzgebietverwaltung", [
|
|
"GET_URL" => $this::getUrl("ADBNetzgebiet/getNetzgebiete"),
|
|
"SAVE_URL" => $this::getUrl("ADBNetzgebiet/save"),
|
|
"HISTORY_URL" => $this::getUrl("ADBNetzgebiet/getHistory"),
|
|
"START_RIMO_IMPORT_URL" => $this::getUrl("ADBNetzgebiet/startRimoImport"),
|
|
"GET_RIMO_IMPORT_STATUS_URL" => $this::getUrl("ADBNetzgebiet/getRimoImportStatus"),
|
|
"GET_RIMO_IMPORT_LOG_URL" => $this::getUrl("ADBNetzgebiet/getRimoImportLog"),
|
|
"NETWORK_URL" => $this::getUrl("Network/Index"),
|
|
"NETWORK_CREATE_URL" => $this::getUrl("Network/add"),
|
|
"CAMPAIGN_URL" => $this::getUrl("Preordercampaign/edit"),
|
|
"CAMPAIGN_CREATE_URL" => $this::getUrl("Preordercampaign/add"),
|
|
"CONSENT_URL" => $this::getUrl("ConstructionConsentProject/edit"),
|
|
"CONSENT_CREATE_URL" => $this::getUrl("ConstructionConsentProject/add"),
|
|
"HIDE_PAGE_TITLE" => true,
|
|
"USER_ID" => $this->me->id,
|
|
]);
|
|
}
|
|
|
|
protected function getNetzgebieteAction(): void {
|
|
$filter = [];
|
|
if (!empty($_GET['name'])) $filter['name'] = $_GET['name'];
|
|
if (!empty($_GET['extref'])) $filter['extref'] = $_GET['extref'];
|
|
if (!empty($_GET['source'])) $filter['=source'] = $_GET['source'];
|
|
if (!empty($_GET['source_id'])) $filter['source_id'] = $_GET['source_id'];
|
|
|
|
$allNetzgebiete = ADBNetzgebiet::getAll($filter, null, 0, ['column' => 'name', 'dir' => 'ASC']);
|
|
|
|
$response = [];
|
|
foreach ($allNetzgebiete as $netzgebiet) {
|
|
$response[] = [
|
|
'netzgebiet' => $netzgebiet->toArray(),
|
|
'related' => [
|
|
'networks' => $netzgebiet->relations->networks,
|
|
'campaigns' => $netzgebiet->relations->campaigns,
|
|
'consent_projects' => $netzgebiet->relations->consentProjects
|
|
]
|
|
];
|
|
}
|
|
|
|
self::returnJson(['success' => true, 'data' => $response, 'total' => count($response)]);
|
|
}
|
|
|
|
protected function saveAction(): void {
|
|
$data = $this->postData;
|
|
if (empty($data)) { self::sendError("No data received."); return; }
|
|
|
|
$isNew = empty($data['id']);
|
|
$model = $isNew ? new ADBNetzgebiet() : ADBNetzgebiet::get($data['id']);
|
|
if (!$model) { self::sendError("Netzgebiet not found."); return; }
|
|
|
|
if (isset($data['name'])) $model->name = trim($data['name']) ?: null;
|
|
if (array_key_exists('extref', $data)) $model->extref = trim($data['extref']) ?: null;
|
|
if (array_key_exists('rimo_id', $data)) $model->rimo_id = trim($data['rimo_id']) ?: null;
|
|
if (isset($data['source'])) $model->source = $data['source'] ?: null;
|
|
if (array_key_exists('source_id', $data)) $model->source_id = trim($data['source_id']) ?: null;
|
|
if (array_key_exists('borderpoly', $data)) $model->borderpoly = $data['borderpoly'] ?: null;
|
|
|
|
if (isset($data['freigabe'])) {
|
|
$model->freigabe = is_array($data['freigabe'])
|
|
? json_encode(array_values($data['freigabe']))
|
|
: $data['freigabe'];
|
|
}
|
|
|
|
if (isset($data['options'])) {
|
|
if (is_array($data['options'])) {
|
|
$options = $data['options'];
|
|
if (isset($options['mph_min_homes_tool_automatic_count'])) {
|
|
$options['mph_min_homes_tool_automatic_count'] = (int)$options['mph_min_homes_tool_automatic_count'];
|
|
}
|
|
$boolFields = ['create_address_parts', 'update_freigabe', 'update_address',
|
|
'hausnummer_dont_overwrite_netzgebiet', 'create_preorder', 'preorder_only_oaid',
|
|
'wo_ignore_status', 'delete_units', 'unit_create_oaid'];
|
|
foreach ($boolFields as $field) {
|
|
if (isset($options[$field])) $options[$field] = $options[$field] ? 1 : 0;
|
|
}
|
|
$model->options = json_encode($options);
|
|
} else {
|
|
$model->options = $data['options'];
|
|
}
|
|
}
|
|
|
|
if (!$model->save()) { self::sendError("Failed to save Netzgebiet."); return; }
|
|
|
|
self::returnJson([
|
|
'success' => true,
|
|
'message' => $isNew ? 'Netzgebiet created.' : 'Netzgebiet saved.',
|
|
'id' => $model->getId()
|
|
]);
|
|
}
|
|
|
|
protected function getHistoryAction(): void {
|
|
$id = $_GET['id'] ?? $this->postData['id'] ?? null;
|
|
if (empty($id)) { self::sendError("ID required."); return; }
|
|
|
|
$model = ADBNetzgebiet::get($id);
|
|
if (!$model) { self::sendError("Netzgebiet not found."); return; }
|
|
|
|
$history = $model->getJournalHistory();
|
|
$userIds = array_unique(array_filter(array_column($history, 'user_id')));
|
|
$users = [];
|
|
|
|
foreach ($userIds as $userId) {
|
|
$user = new User($userId);
|
|
if ($user->id) $users[$user->id] = $user->name ?? 'User #' . $user->id;
|
|
}
|
|
|
|
foreach ($history as $entry) {
|
|
$entry->user_name = $users[$entry->user_id] ?? 'System';
|
|
}
|
|
|
|
self::returnJson(['success' => true, 'data' => $history]);
|
|
}
|
|
|
|
protected function startRimoImportAction(): void {
|
|
$id = $_GET['id'] ?? null;
|
|
if (empty($id)) {
|
|
self::returnJson(['success' => false, 'message' => "Netzgebiet ID required."]);
|
|
return;
|
|
}
|
|
|
|
$netzgebiet = ADBNetzgebiet::get($id);
|
|
if (!$netzgebiet || !$netzgebiet->id) {
|
|
self::returnJson(['success' => false, 'message' => "Netzgebiet not found."]);
|
|
return;
|
|
}
|
|
|
|
if (strpos($netzgebiet->source, 'rimo-') !== 0) {
|
|
self::returnJson(['success' => false, 'message' => "This action is only for RIMO-source Netzgebiete."]);
|
|
return;
|
|
}
|
|
|
|
if (empty($netzgebiet->source_id)) {
|
|
self::returnJson(['success' => false, 'message' => "Netzgebiet has no Source ID."]);
|
|
return;
|
|
}
|
|
|
|
$safeSourceId = preg_replace('/[^a-zA-Z0-9_-]/', '_', $netzgebiet->source_id);
|
|
$importTempDir = TEMP_DIR . "/ADBNetzgebietRimoImport/";
|
|
$logDir = $importTempDir . $safeSourceId;
|
|
$logFile = $logDir . "/import.log";
|
|
$lockFile = $logDir . "/import.lock";
|
|
|
|
if (is_dir($importTempDir)) {
|
|
foreach (glob($importTempDir . "*") as $dir) {
|
|
if (is_dir($dir) && (time() - filemtime($dir)) > 86400) {
|
|
// simple cleanup
|
|
if (file_exists($dir . "/import.log")) @unlink($dir . "/import.log");
|
|
if (file_exists($dir . "/import.lock")) @unlink($dir . "/import.lock");
|
|
@rmdir($dir);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_dir($logDir)) {
|
|
mkdir($logDir, 0755, true);
|
|
}
|
|
|
|
if (file_exists($lockFile)) {
|
|
if ((time() - filemtime($lockFile)) > 3600) { // stale lock for 1h
|
|
@unlink($lockFile);
|
|
} else {
|
|
self::returnJson(['success' => false, 'message' => "Import is already running.", 'status' => 'running']);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (file_exists($logFile) && (time() - filemtime($logFile)) < 900) {
|
|
$remaining = 900 - (time() - filemtime($logFile));
|
|
self::returnJson(['success' => false, 'message' => "Please wait before starting another import.", 'status' => 'cooldown', 'remaining' => $remaining]);
|
|
return;
|
|
}
|
|
|
|
touch($lockFile);
|
|
|
|
$projectRoot = dirname(dirname(__DIR__));
|
|
$scriptRelativePath = 'scripts/adb-rimo-import/rimo-import.php';
|
|
$scriptFullPath = $projectRoot . '/' . $scriptRelativePath;
|
|
|
|
if (!file_exists($scriptFullPath)) {
|
|
self::returnJson(['success' => false, 'message' => "Import script not found."]);
|
|
return;
|
|
}
|
|
|
|
$php_executable = "php";
|
|
$command = "$php_executable $scriptRelativePath " . escapeshellarg($netzgebiet->source_id);
|
|
|
|
$bgCommand = 'cd ' . escapeshellarg($projectRoot) . ' && ' . $command . ' > ' . escapeshellarg($logFile) . ' 2>&1 & echo $!';
|
|
$pid = shell_exec($bgCommand);
|
|
|
|
if(empty($pid) || !is_numeric(trim($pid))) {
|
|
self::returnJson(['success' => false, 'message' => "Failed to start background process."]);
|
|
return;
|
|
}
|
|
|
|
file_put_contents($lockFile, trim($pid));
|
|
|
|
self::returnJson(['success' => true, 'message' => 'RIMO import started.']);
|
|
}
|
|
|
|
protected function getRimoImportStatusAction(): void {
|
|
$ids = $this->postData['ids'] ?? [];
|
|
if (empty($ids)) {
|
|
self::returnJson(['success' => true, 'data' => []]);
|
|
return;
|
|
}
|
|
|
|
$statuses = [];
|
|
foreach ($ids as $id) {
|
|
$netzgebiet = ADBNetzgebiet::get($id);
|
|
if (!$netzgebiet || !$netzgebiet->id || strpos($netzgebiet->source, 'rimo-') !== 0 || empty($netzgebiet->source_id)) {
|
|
$statuses[$id] = ['status' => 'not_applicable'];
|
|
continue;
|
|
}
|
|
|
|
$safeSourceId = preg_replace('/[^a-zA-Z0-9_-]/', '_', $netzgebiet->source_id);
|
|
$logDir = TEMP_DIR . "/ADBNetzgebietRimoImport/" . $safeSourceId;
|
|
$logFile = $logDir . "/import.log";
|
|
$lockFile = $logDir . "/import.lock";
|
|
|
|
if (file_exists($lockFile)) {
|
|
$pid = trim(file_get_contents($lockFile));
|
|
// Check if process is still running. posix_getpgid returns false if process does not exist.
|
|
if (is_numeric($pid) && posix_getpgid((int)$pid) !== false) {
|
|
$statuses[$id] = ['status' => 'running'];
|
|
} else {
|
|
// Stale lock file, process is gone.
|
|
@unlink($lockFile);
|
|
// Check for cooldown based on log file from the finished process
|
|
if (file_exists($logFile) && (time() - filemtime($logFile)) < 900) {
|
|
$statuses[$id] = [
|
|
'status' => 'cooldown',
|
|
'remaining' => 900 - (time() - filemtime($logFile))
|
|
];
|
|
} else {
|
|
$statuses[$id] = ['status' => 'idle'];
|
|
}
|
|
}
|
|
} elseif (file_exists($logFile) && (time() - filemtime($logFile)) < 900) {
|
|
$statuses[$id] = [
|
|
'status' => 'cooldown',
|
|
'remaining' => 900 - (time() - filemtime($logFile))
|
|
];
|
|
} else {
|
|
$statuses[$id] = ['status' => 'idle'];
|
|
}
|
|
}
|
|
self::returnJson(['success' => true, 'data' => $statuses]);
|
|
}
|
|
|
|
protected function getRimoImportLogAction(): void {
|
|
$id = $_GET['id'] ?? null;
|
|
if (empty($id)) {
|
|
self::returnJson(['success' => false, 'message' => "Netzgebiet ID required."]);
|
|
return;
|
|
}
|
|
|
|
$netzgebiet = ADBNetzgebiet::get($id);
|
|
if (!$netzgebiet || !$netzgebiet->id || empty($netzgebiet->source_id)) {
|
|
self::returnJson(['success' => false, 'message' => "Netzgebiet not found or not applicable."]);
|
|
return;
|
|
}
|
|
|
|
$safeSourceId = preg_replace('/[^a-zA-Z0-9_-]/', '_', $netzgebiet->source_id);
|
|
$logDir = TEMP_DIR . "/ADBNetzgebietRimoImport/" . $safeSourceId;
|
|
$logFile = $logDir . "/import.log";
|
|
$lockFile = $logDir . "/import.lock";
|
|
|
|
$logContent = "";
|
|
if (file_exists($logFile)) {
|
|
$logContent = file_get_contents($logFile);
|
|
}
|
|
|
|
$status = 'idle';
|
|
if (file_exists($lockFile)) {
|
|
$pid = trim(file_get_contents($lockFile));
|
|
if (is_numeric($pid) && posix_getpgid((int)$pid) !== false) {
|
|
$status = 'running';
|
|
} else {
|
|
@unlink($lockFile); // Stale lock, process is gone
|
|
}
|
|
}
|
|
|
|
if ($status !== 'running') {
|
|
if (file_exists($logFile) && (time() - filemtime($logFile)) < 900) {
|
|
$status = 'cooldown';
|
|
} else {
|
|
$status = file_exists($logFile) ? 'finished' : 'idle';
|
|
}
|
|
}
|
|
|
|
self::returnJson([
|
|
'success' => true,
|
|
'data' => [
|
|
'log' => $logContent,
|
|
'status' => $status,
|
|
'timestamp' => file_exists($logFile) ? filemtime($logFile) : null
|
|
]
|
|
]);
|
|
}
|
|
|
|
// TODO: Implement RIMO API check
|
|
protected function checkRimoSourceIdAction(): void {
|
|
self::returnJson(['success' => false, 'message' => "RIMO API check not available."]);
|
|
}
|
|
}
|