8 private function cms() {
9 return dbx()->get_include_obj(
'dbxKiCmsService',
'dbxKi');
12 private function bundle() {
13 return dbx()->get_include_obj(
'dbxKiBundleService',
'dbxKi');
16 private function briefing() {
17 return dbx()->get_include_obj(
'dbxKiBriefingService',
'dbxKi');
20 private function moduleBriefing() {
21 return dbx()->get_include_obj(
'dbxKiModuleBriefingService',
'dbxKi');
24 private function design() {
25 return dbx()->get_include_obj(
'dbxKiDesignService',
'dbxKi');
28 private function help() {
29 return dbx()->get_include_obj(
'dbxKiHelp',
'dbxKi');
32 private function provision() {
33 require_once __DIR__ .
'/include/dbxKiCmsHelpProvision.class.php';
37 private function html_start():
string {
38 require_once __DIR__ .
'/include/dbxKiCmsHelpProvision.class.php';
41 $briefing =
'?dbx_modul=dbxKi&dbx_run1=briefing';
42 $bundle =
'?dbx_modul=dbxKi&dbx_run1=bundle';
43 $design =
'?dbx_modul=dbxKi&dbx_run1=briefing_design';
44 $syncAll =
'?dbx_modul=dbxKi&dbx_run1=translation_sync_all';
45 $api =
'?dbx_modul=dbxKi&dbx_run1=api';
47 return '<div class="container py-4">'
49 .
'<p>Formular-basierte KI-Auftraege fuer das Content-CMS.</p>'
50 .
'<div class="d-flex flex-wrap gap-2 mb-3">'
51 .
'<a class="btn btn-primary" href="' . htmlspecialchars($briefing, ENT_QUOTES,
'UTF-8') .
'">KI-Auftrag starten</a>'
52 .
'<a class="btn btn-outline-primary" href="' . htmlspecialchars($syncAll, ENT_QUOTES,
'UTF-8') .
'">Sprache komplett uebersetzen</a>'
53 .
'<a class="btn btn-outline-primary" href="' . htmlspecialchars($bundle, ENT_QUOTES,
'UTF-8') .
'">Bundle importieren</a>'
54 .
'<a class="btn btn-outline-primary" href="' . htmlspecialchars(
$design, ENT_QUOTES,
'UTF-8') .
'">Design entwickeln</a>'
55 .
'<a class="btn btn-outline-secondary" href="' . htmlspecialchars($anleitungUrl, ENT_QUOTES,
'UTF-8') .
'">Anleitung</a>'
57 .
'<p class="small text-muted">Ablauf: Formular → ZIP an ChatGPT → fertige ZIP importieren und ausfuehren.</p>'
58 .
'<p><strong>API:</strong> <code>' . htmlspecialchars(
$api, ENT_QUOTES,
'UTF-8') .
'</code></p>'
62 private function esc(
$value):
string {
63 return htmlspecialchars((
string)
$value, ENT_QUOTES,
'UTF-8');
66 private function language_options(
string $selected):
string {
69 $sel =
$lng === $selected ?
' selected' :
'';
70 $html .=
'<option value="' . $this->esc(
$lng) .
'"' . $sel .
'>' . $this->esc(strtoupper(
$lng)) .
'</option>';
75 private function target_language_checkboxes(
string $sourceLng, array $selected):
string {
78 if (
$lng === $sourceLng) {
81 $checked = in_array(
$lng, $selected,
true) ?
' checked' :
'';
82 $html .=
'<label class="form-check form-check-inline">'
83 .
'<input class="form-check-input" type="checkbox" name="target_lngs[]" value="' . $this->esc(
$lng) .
'"' .
$checked .
'>'
84 .
'<span class="form-check-label">' . $this->esc(strtoupper(
$lng)) .
'</span>'
87 return $html !==
'' ?
$html :
'<span class="text-muted">Keine weitere aktive Sprache vorhanden.</span>';
90 private function translation_sync_params_from_request(): array {
91 $sourceLng = strtolower(trim((
string)
dbx()->get_request_var(
'source_lng', \
dbx\
dbxContent\dbxContentLngSync::masterLng(),
'*')));
92 $targets =
dbx()->get_request_var(
'target_lngs', array(),
'*');
100 'source_lng' => $sourceLng,
101 'target_lngs' => array_values(array_filter(array_map(
static function(
$lng) {
102 return strtolower(trim((
string)
$lng));
104 'root_folder_id' => max(0, (
int)
dbx()->get_request_var(
'root_folder_id', 0,
'*')),
105 'update_existing' => !array_key_exists(
'sync_mode', $_REQUEST) ||
dbx()->get_request_var(
'update_existing',
'0',
'*') ===
'1' ? 1 : 0,
106 'skip_manual' =>
dbx()->get_request_var(
'skip_manual',
'0',
'*') ===
'1' ? 1 : 0,
107 'copy_media' => !array_key_exists(
'sync_mode', $_REQUEST) ||
dbx()->get_request_var(
'copy_media',
'0',
'*') ===
'1' ? 1 : 0,
108 'replace_media_usage' =>
dbx()->get_request_var(
'replace_media_usage',
'0',
'*') ===
'1' ? 1 : 0,
123 private function translation_sync_form(array $replacements = array()) {
124 $form =
dbx()->get_system_obj(
'dbxForm');
125 $form->init(
'ki-translation-sync-all',
'ki-translation-sync-all');
126 $form->_action =
'?dbx_modul=dbxKi&dbx_run1=translation_sync_all';
127 $form->_msg_info =
'';
128 foreach ($replacements as $key =>
$value) {
134 private function render_translation_sync_all():
string {
135 $params = $this->translation_sync_params_from_request();
136 $form = $this->translation_sync_form();
137 $hasPost = array_key_exists(
'sync_mode',
$_POST);
138 $hasSubmitted = (bool)
$form->submit();
139 if (!$hasSubmitted && !count($params[
'target_lngs'])) {
141 if (
$lng !== $params[
'source_lng']) {
142 $params[
'target_lngs'][] =
$lng;
147 $mode = strtolower(trim((
string)
dbx()->get_request_var(
'sync_mode',
'',
'*')));
149 if ($hasPost && !$hasSubmitted) {
150 $resultHtml =
'<div class="alert alert-danger">Ungueltiger oder abgelaufener Formular-Token.</div>';
151 } elseif ($hasSubmitted && (
$mode ===
'preview' ||
$mode ===
'execute')) {
153 $plan = $this->cms()->bundleBuildPlan(
'translation.sync_all', $params);
154 if (
$mode ===
'execute') {
155 $result = $this->cms()->bundleExecutePlan(
'translation.sync_all', $params,
$plan);
156 $resultHtml = $this->translation_sync_result_html(
$result,
true);
158 $resultHtml = $this->translation_sync_plan_html(
$plan);
160 }
catch (\Throwable $e) {
161 $resultHtml =
'<div class="alert alert-danger">' . $this->esc($e->getMessage()) .
'</div>';
165 $replacements = array_merge(array(
166 'action' =>
'?dbx_modul=dbxKi&dbx_run1=translation_sync_all',
167 'language_options' => $this->language_options($params[
'source_lng']),
168 'target_language_checkboxes' => $this->target_language_checkboxes($params[
'source_lng'], $params[
'target_lngs']),
169 'root_folder_id' => $this->esc((
string)$params[
'root_folder_id']),
170 'update_existing_checked' => (
int)$params[
'update_existing'] === 1 ?
'checked' :
'',
171 'skip_manual_checked' => (
int)$params[
'skip_manual'] === 1 ?
'checked' :
'',
172 'copy_media_checked' => (
int)$params[
'copy_media'] === 1 ?
'checked' :
'',
173 'replace_media_usage_checked' => (
int)$params[
'replace_media_usage'] === 1 ?
'checked' :
'',
174 'result_html' => $resultHtml,
175 ), $this->help()->moduleBarTemplateData(
176 'translation_sync_all',
177 '<a class="btn btn-outline-secondary btn-sm" href="?dbx_modul=dbxKi"><i class="bi bi-arrow-left"></i> Zurueck</a>'
180 foreach ($replacements as $key =>
$value) {
186 private function translation_sync_plan_html(array
$plan):
string {
187 $counts = is_array(
$plan[
'counts'] ??
null) ?
$plan[
'counts'] : array();
188 $targets = is_array(
$plan[
'target_lngs'] ??
null) ? implode(
', ', array_map(
'strtoupper',
$plan[
'target_lngs'])) :
'';
189 return '<div class="alert alert-info">'
190 .
'<strong>Vorschau:</strong> '
191 . $this->esc((
string)($counts[
'folders'] ?? 0)) .
' Ordner und '
192 . $this->esc((
string)($counts[
'pages'] ?? 0)) .
' Seiten von '
193 . $this->esc(strtoupper((
string)(
$plan[
'source_lng'] ??
''))) .
' nach '
194 . $this->esc(
$targets) .
'. Provider: '
195 . $this->esc((
string)(
$plan[
'provider'] ??
'')) .
'.'
199 private function translation_sync_result_html(array
$result,
bool $executed):
string {
200 $folders = is_array(
$result[
'folders'] ??
null) ?
$result[
'folders'] : array();
203 $warnings = is_array(
$result[
'warnings'] ??
null) ?
$result[
'warnings'] : array();
205 $html =
'<div class="alert ' .
$class .
'"><strong>' . ($executed ?
'Ausgefuehrt.' :
'Ergebnis.') .
'</strong> '
206 .
'Ordner: ' . count($folders[
'created'] ?? array()) .
' neu, ' . count($folders[
'updated'] ?? array()) .
' aktualisiert. '
207 .
'Seiten: ' . count(
$pages[
'created'] ?? array()) .
' neu, ' . count(
$pages[
'updated'] ?? array()) .
' aktualisiert. '
208 .
'Medienzuordnungen: ' . (int)(
$result[
'media_copied'] ?? 0) .
'.</div>';
210 $html .=
'<div class="card p-3 mb-3"><h2 class="h6">Fehler</h2><ul class="mb-0">';
212 $html .=
'<li>' . $this->esc($error) .
'</li>';
214 $html .=
'</ul></div>';
216 if (count($warnings)) {
217 $html .=
'<div class="card p-3 mb-3"><h2 class="h6">Hinweise</h2><ul class="mb-0">';
220 $html .=
'<li>' . $this->esc(trim($msg)) .
'</li>';
222 $html .=
'</ul></div>';
227 private function html_provision_result(array
$result):
string {
229 $class =
$ok ?
'alert-success' :
'alert-danger';
230 $msg =
$ok ?
'CMS-Anleitung provisioniert.' :
'Provision fehlgeschlagen.';
232 $back =
'?dbx_modul=dbxKi';
234 return '<div class="container py-4">'
235 .
'<div class="alert ' .
$class .
'">' . htmlspecialchars($msg, ENT_QUOTES,
'UTF-8') .
'</div>'
236 .
'<pre class="bg-light p-3 rounded">' . htmlspecialchars(json_encode(
$result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), ENT_QUOTES,
'UTF-8') .
'</pre>'
237 .
'<div class="d-flex flex-wrap gap-2">'
238 .
'<a class="btn btn-primary" href="' . htmlspecialchars($pageUrl, ENT_QUOTES,
'UTF-8') .
'">Zur Anleitung</a>'
239 .
'<a class="btn btn-outline-secondary" href="' . htmlspecialchars($back, ENT_QUOTES,
'UTF-8') .
'">dbxKi Uebersicht</a>'
243 private function html_error(
string $message,
string $backUrl):
string {
244 return '<div class="container py-4"><div class="alert alert-danger">'
245 . htmlspecialchars($message, ENT_QUOTES,
'UTF-8')
246 .
'</div><p><a class="btn btn-secondary" href="' . htmlspecialchars($backUrl, ENT_QUOTES,
'UTF-8') .
'">Zurueck</a></p></div>';
249 public function run($action =
'') {
250 if ($action ===
'') {
251 $action =
dbx()->get_modul_var(
'dbx_run1',
'start',
'parameter');
259 $this->cms()->handle($action);
263 return $this->briefing()->renderHub();
265 case 'briefing_module':
266 return $this->moduleBriefing()->renderBriefing();
268 case 'briefing_module_export':
269 $this->moduleBriefing()->handleExport();
272 case 'briefing_design':
273 return $this->design()->renderBriefing();
275 case 'briefing_design_export':
277 $this->design()->handleExport();
278 }
catch (\Throwable $e) {
279 dbx()->sys_msg(
'error',
'dbxKi',
'briefing_design_export',
'Design-Export fehlgeschlagen', $e->getMessage());
280 return $this->html_error($e->getMessage(),
'?dbx_modul=dbxKi&dbx_run1=briefing_design');
284 case 'design_bundle_import':
285 return $this->design()->handleImport();
287 case 'design_bundle_apply':
288 return $this->design()->handleApply();
290 case 'module_bundle':
291 return $this->moduleBriefing()->renderBundleStart();
293 case 'module_bundle_import':
294 return $this->moduleBriefing()->handleBundleImport();
297 $this->moduleBriefing()->handleApi();
300 case 'briefing_page_create':
301 return $this->briefing()->renderPageCreateForm();
303 case 'briefing_page_update':
304 return $this->briefing()->renderPageUpdateForm();
306 case 'briefing_page_update_preview':
307 $this->briefing()->handlePageUpdatePreviewJson();
310 case 'briefing_page_translate':
311 return $this->briefing()->renderPageTranslateForm();
313 case 'translation_sync_all':
314 return $this->render_translation_sync_all();
316 case 'briefing_styles':
317 return $this->briefing()->renderStylesAdmin();
319 case 'briefing_styles_save':
320 return $this->briefing()->handleStylesSave();
322 case 'briefing_styles_reset':
323 return $this->briefing()->handleStylesReset();
325 case 'briefing_export':
327 $this->briefing()->handleExport();
328 }
catch (\Throwable $e) {
329 dbx()->sys_msg(
'error',
'dbxKi',
'briefing_export',
'Export fehlgeschlagen', $e->getMessage());
330 $recipe = strtolower(trim((
string)
dbx()->get_request_var(
'recipe',
'',
'*')));
331 return $this->html_error($e->getMessage(), $this->briefing()->exportBackUrl($recipe));
336 return $this->bundle()->renderStartPage();
338 case 'bundle_import':
339 return $this->bundle()->handleImport();
341 case 'bundle_process':
342 return $this->bundle()->handleProcess();
344 case 'bundle_export':
345 $this->bundle()->handleExport();
348 case 'bundle_describe':
349 $this->bundle()->handleDescribeJson();
353 return $this->help()->renderHelpWindow();
355 case 'provision_anleitung':
356 require_once __DIR__ .
'/include/dbxKiCmsHelpProvision.class.php';
358 if (empty(
$result[
'errors'])) {
366 return $this->html_provision_result(
$result);
370 require_once __DIR__ .
'/include/dbxKiCmsHelpProvision.class.php';
371 return $this->html_start();
foreach($rows as $row) $targets