Files
backPRO/templates/sites/edit.php
Jacek Pyziak b653cea252 Add installer functionality for WordPress with FTP and database configuration
- Create SQL migration for prompt templates used in article and image generation.
- Add migration to change publish interval from days to hours in the sites table.
- Implement InstallerController to handle installation requests and validation.
- Develop FtpService for FTP connections and file uploads.
- Create InstallerService to manage the WordPress installation process, including downloading, extracting, and configuring WordPress.
- Add index view for the installer with form inputs for FTP, database, and WordPress admin settings.
- Implement progress tracking for the installation process with AJAX polling.
2026-02-16 21:55:24 +01:00

293 lines
18 KiB
PHP

<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Edytuj stronę: <?= htmlspecialchars($site['name']) ?></h2>
<div class="d-flex gap-2">
<form method="post" action="/publish/site/<?= $site['id'] ?>" class="d-inline">
<button type="submit" class="btn btn-success" onclick="return confirm('Opublikować artykuł na tej stronie teraz?')">
<i class="bi bi-play-circle me-1"></i>Publikuj teraz
</button>
</form>
</div>
</div>
<div class="row g-4">
<div class="col-lg-7">
<div class="card">
<div class="card-header"><h5 class="mb-0">Ustawienia strony</h5></div>
<div class="card-body">
<form method="post" action="/sites/<?= $site['id'] ?>">
<div class="mb-3">
<label for="name" class="form-label">Nazwa strony</label>
<input type="text" class="form-control" id="name" name="name" value="<?= htmlspecialchars($site['name']) ?>" required>
</div>
<div class="mb-3">
<label for="url" class="form-label">URL WordPressa</label>
<input type="url" class="form-control" id="url" name="url" value="<?= htmlspecialchars($site['url']) ?>" required>
</div>
<div class="mb-3">
<label for="api_user" class="form-label">Użytkownik API</label>
<input type="text" class="form-control" id="api_user" name="api_user" value="<?= htmlspecialchars($site['api_user']) ?>" required>
</div>
<div class="mb-3">
<label for="api_token" class="form-label">Application Password</label>
<input type="text" class="form-control" id="api_token" name="api_token" value="<?= htmlspecialchars($site['api_token']) ?>" required>
</div>
<div class="mb-3">
<label for="publish_interval_hours" class="form-label">Interwał publikacji (godziny)</label>
<input type="number" class="form-control" id="publish_interval_hours" name="publish_interval_hours" value="<?= $site['publish_interval_hours'] ?>" min="1" max="720">
</div>
<div class="mb-3">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="is_multisite" name="is_multisite" value="1" <?= $site['is_multisite'] ? 'checked' : '' ?>>
<label class="form-check-label" for="is_multisite">Strona wielotematyczna</label>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="is_active" name="is_active" value="1" <?= $site['is_active'] ? 'checked' : '' ?>>
<label class="form-check-label" for="is_active">Aktywna</label>
</div>
</div>
<!-- Credentials accordion -->
<?php $hasCredentials = !empty($site['ftp_host']) || !empty($site['db_host']) || !empty($site['wp_admin_user']); ?>
<div class="accordion mb-3" id="credentialsAccordion">
<div class="accordion-item border-0">
<h2 class="accordion-header">
<button class="accordion-button collapsed bg-light px-0" type="button" data-bs-toggle="collapse" data-bs-target="#credentialsPanel">
<i class="bi bi-key me-2"></i>Dane dostępowe (FTP, baza danych, panel WP)
<?php if ($hasCredentials): ?>
<span class="badge bg-success ms-2">zapisane</span>
<?php else: ?>
<span class="badge bg-secondary ms-2">brak</span>
<?php endif; ?>
</button>
</h2>
<div id="credentialsPanel" class="accordion-collapse collapse">
<div class="accordion-body px-0 pb-0">
<!-- FTP -->
<fieldset class="border rounded p-3 mb-3">
<legend class="float-none w-auto px-2 fs-6 fw-bold mb-0">
<i class="bi bi-hdd-network me-1"></i>FTP
</legend>
<div class="row mb-2">
<div class="col-md-8">
<label for="ftp_host" class="form-label small">Host</label>
<input type="text" class="form-control form-control-sm" id="ftp_host" name="ftp_host" value="<?= htmlspecialchars($site['ftp_host'] ?? '') ?>" placeholder="ftp.example.com">
</div>
<div class="col-md-4">
<label for="ftp_port" class="form-label small">Port</label>
<input type="number" class="form-control form-control-sm" id="ftp_port" name="ftp_port" value="<?= htmlspecialchars($site['ftp_port'] ?? '21') ?>">
</div>
</div>
<div class="row mb-2">
<div class="col-md-6">
<label for="ftp_user" class="form-label small">Użytkownik</label>
<input type="text" class="form-control form-control-sm" id="ftp_user" name="ftp_user" value="<?= htmlspecialchars($site['ftp_user'] ?? '') ?>">
</div>
<div class="col-md-6">
<label for="ftp_pass" class="form-label small">Hasło</label>
<input type="password" class="form-control form-control-sm" id="ftp_pass" name="ftp_pass" value="<?= htmlspecialchars($site['ftp_pass'] ?? '') ?>">
</div>
</div>
<div>
<label for="ftp_path" class="form-label small">Ścieżka</label>
<input type="text" class="form-control form-control-sm" id="ftp_path" name="ftp_path" value="<?= htmlspecialchars($site['ftp_path'] ?? '') ?>" placeholder="/public_html">
</div>
</fieldset>
<!-- Database -->
<fieldset class="border rounded p-3 mb-3">
<legend class="float-none w-auto px-2 fs-6 fw-bold mb-0">
<i class="bi bi-database me-1"></i>Baza danych
</legend>
<div class="row mb-2">
<div class="col-md-6">
<label for="db_host" class="form-label small">Host</label>
<input type="text" class="form-control form-control-sm" id="db_host" name="db_host" value="<?= htmlspecialchars($site['db_host'] ?? '') ?>" placeholder="localhost">
</div>
<div class="col-md-6">
<label for="db_name" class="form-label small">Nazwa bazy</label>
<input type="text" class="form-control form-control-sm" id="db_name" name="db_name" value="<?= htmlspecialchars($site['db_name'] ?? '') ?>">
</div>
</div>
<div class="row mb-2">
<div class="col-md-4">
<label for="db_user" class="form-label small">Użytkownik</label>
<input type="text" class="form-control form-control-sm" id="db_user" name="db_user" value="<?= htmlspecialchars($site['db_user'] ?? '') ?>">
</div>
<div class="col-md-4">
<label for="db_pass" class="form-label small">Hasło</label>
<input type="password" class="form-control form-control-sm" id="db_pass" name="db_pass" value="<?= htmlspecialchars($site['db_pass'] ?? '') ?>">
</div>
<div class="col-md-4">
<label for="db_prefix" class="form-label small">Prefix</label>
<input type="text" class="form-control form-control-sm" id="db_prefix" name="db_prefix" value="<?= htmlspecialchars($site['db_prefix'] ?? 'wp_') ?>">
</div>
</div>
</fieldset>
<!-- WP Admin -->
<fieldset class="border rounded p-3">
<legend class="float-none w-auto px-2 fs-6 fw-bold mb-0">
<i class="bi bi-wordpress me-1"></i>Panel administratora
</legend>
<div class="row mb-2">
<div class="col-md-6">
<label for="wp_admin_user" class="form-label small">Login</label>
<input type="text" class="form-control form-control-sm" id="wp_admin_user" name="wp_admin_user" value="<?= htmlspecialchars($site['wp_admin_user'] ?? '') ?>">
</div>
<div class="col-md-6">
<label for="wp_admin_pass" class="form-label small">Hasło</label>
<input type="password" class="form-control form-control-sm" id="wp_admin_pass" name="wp_admin_pass" value="<?= htmlspecialchars($site['wp_admin_pass'] ?? '') ?>">
</div>
</div>
<div>
<label for="wp_admin_email" class="form-label small">E-mail</label>
<input type="email" class="form-control form-control-sm" id="wp_admin_email" name="wp_admin_email" value="<?= htmlspecialchars($site['wp_admin_email'] ?? '') ?>">
</div>
</fieldset>
</div>
</div>
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">Zapisz zmiany</button>
<a href="/sites" class="btn btn-outline-secondary">Anuluj</a>
<button class="btn btn-outline-success btn-test-connection ms-auto" data-site-id="<?= $site['id'] ?>" type="button">
<i class="bi bi-wifi me-1"></i>Test
</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-lg-5">
<!-- Assigned topics -->
<div class="card mb-4">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">Tematy (<?= count($topics) ?>)</h5>
<a href="/sites/<?= $site['id'] ?>/topics" class="btn btn-sm btn-outline-info">
<i class="bi bi-pencil me-1"></i>Zarządzaj
</a>
</div>
<div class="card-body p-0">
<?php if (empty($topics)): ?>
<div class="p-3 text-muted text-center">Brak tematów. Dodaj z biblioteki poniżej.</div>
<?php else: ?>
<table class="table table-hover table-sm mb-0">
<thead>
<tr>
<th>Temat</th>
<th>Kategoria</th>
<th>Art.</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($topics as $topic): ?>
<tr>
<td>
<?= htmlspecialchars($topic['name']) ?>
<?php if (!$topic['is_active']): ?>
<span class="badge bg-secondary">off</span>
<?php endif; ?>
</td>
<td class="small text-muted"><?= htmlspecialchars($topic['global_category_name'] ?? '') ?></td>
<td><span class="badge bg-primary"><?= $topic['article_count'] ?></span></td>
<td>
<button class="btn btn-sm btn-outline-danger py-0 px-1 btn-delete-topic" data-id="<?= $topic['id'] ?>" data-name="<?= htmlspecialchars($topic['name']) ?>">
<i class="bi bi-x"></i>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
<!-- Quick add from library -->
<div class="card">
<div class="card-header"><h5 class="mb-0">Dodaj temat z biblioteki</h5></div>
<div class="card-body">
<form method="post" action="/sites/<?= $site['id'] ?>/topics">
<div class="mb-3">
<select class="form-select" name="global_topic_id" id="quick_global_topic" onchange="quickFillTopic(this)" required>
<option value="">Wybierz temat...</option>
<?php foreach ($globalTopics as $cat): ?>
<optgroup label="<?= htmlspecialchars($cat['name']) ?>">
<?php foreach ($cat['children'] as $child): ?>
<?php $alreadyAssigned = in_array($child['id'], $assignedGlobalIds); ?>
<option value="<?= $child['id'] ?>"
data-name="<?= htmlspecialchars($child['name']) ?>"
data-desc="<?= htmlspecialchars($child['description'] ?? '') ?>"
<?= $alreadyAssigned ? 'disabled' : '' ?>>
<?= htmlspecialchars($child['name']) ?><?= $alreadyAssigned ? ' (dodany)' : '' ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?>
</select>
</div>
<input type="hidden" name="name" id="quick_topic_name">
<input type="hidden" name="description" id="quick_topic_desc">
<input type="hidden" name="is_active" value="1">
<button type="submit" class="btn btn-success btn-sm w-100">
<i class="bi bi-plus-lg me-1"></i>Dodaj
</button>
</form>
</div>
</div>
</div>
</div>
<script>
function quickFillTopic(select) {
var opt = select.options[select.selectedIndex];
document.getElementById('quick_topic_name').value = opt.dataset.name || '';
document.getElementById('quick_topic_desc').value = opt.dataset.desc || '';
}
document.querySelectorAll('.btn-delete-topic').forEach(function(btn) {
btn.addEventListener('click', function() {
var id = this.dataset.id;
var name = this.dataset.name;
if (!confirm('Usunąć temat "' + name + '"?')) return;
var row = this.closest('tr');
btn.disabled = true;
fetch('/topics/' + id + '/delete', {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.success) {
row.style.transition = 'opacity .3s';
row.style.opacity = '0';
setTimeout(function() { row.remove(); }, 300);
} else {
alert(data.message || 'Błąd usuwania');
btn.disabled = false;
}
})
.catch(function() {
alert('Błąd połączenia');
btn.disabled = false;
});
});
});
</script>