yeni
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
<title>{% block title %}Hosting Yönetim Paneli{% endblock %}</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
||||
{% block head_extras %}{% endblock %}
|
||||
<style>
|
||||
body {
|
||||
background: #181a1b;
|
||||
@ -13,6 +14,13 @@
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
}
|
||||
|
||||
/* Custom alert styles */
|
||||
.alert.alert-success.alert-dismissible.fade.show {
|
||||
background-color: #333333 !important;
|
||||
color: #ffffff;
|
||||
border-color: #28a745;
|
||||
}
|
||||
|
||||
/* Sidebar Styles */
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
@ -86,13 +94,10 @@
|
||||
|
||||
.nav-dropdown-content {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: #1a1d23;
|
||||
border-left: 3px solid #4fc3f7;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
@ -127,6 +132,10 @@
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-dropdown.active .nav-dropdown-toggle::after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.nav-dropdown.active .nav-dropdown-toggle::after {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
@ -344,10 +353,20 @@
|
||||
<i class="bi bi-speedometer2"></i>
|
||||
Dashboard
|
||||
</a>
|
||||
<a href="{% url 'musteriler' %}" class="nav-item {% if request.resolver_match.url_name == 'musteriler' %}active{% endif %}">
|
||||
<i class="bi bi-people"></i>
|
||||
Müşteriler
|
||||
</a>
|
||||
<div class="nav-dropdown {% if request.resolver_match.url_name == 'musteriler' or request.resolver_match.url_name == 'faturalar' %}active{% endif %}">
|
||||
<a href="#" class="nav-item nav-dropdown-toggle {% if request.resolver_match.url_name == 'musteriler' or request.resolver_match.url_name == 'faturalar' %}active{% endif %}" onclick="toggleDropdown(this); return false;">
|
||||
<i class="bi bi-people"></i>
|
||||
Müşteriler
|
||||
</a>
|
||||
<div class="nav-dropdown-content">
|
||||
<a href="{% url 'musteriler' %}" class="nav-dropdown-item {% if request.resolver_match.url_name == 'musteriler' %}active{% endif %}">
|
||||
<i class="bi bi-person-lines-fill"></i> Müşteri Listesi
|
||||
</a>
|
||||
<a href="{% url 'faturalar' %}" class="nav-dropdown-item {% if request.resolver_match.url_name == 'faturalar' %}active{% endif %}">
|
||||
<i class="bi bi-receipt"></i> Faturalar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{% url 'host_yonetimi' %}" class="nav-item {% if request.resolver_match.url_name == 'host_yonetimi' %}active{% endif %}">
|
||||
<i class="bi bi-hdd-network"></i>
|
||||
Host Yönetimi
|
||||
@ -425,7 +444,7 @@ function showToast(message, type = 'info') {
|
||||
const toast = document.getElementById('mainToast');
|
||||
const toastBody = document.getElementById('mainToastBody');
|
||||
|
||||
toastBody.textContent = message;
|
||||
toastBody.innerHTML = message;
|
||||
|
||||
// Remove existing classes
|
||||
toast.classList.remove('text-bg-dark', 'text-bg-success', 'text-bg-danger', 'text-bg-warning', 'text-bg-info');
|
||||
@ -502,5 +521,9 @@ document.addEventListener('click', function(event) {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- EXTRA SCRIPTS BLOCK -->
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -371,7 +371,7 @@ function refreshAllHosts() {
|
||||
|
||||
// Tüm siteleri kontrol et
|
||||
function checkAllSites() {
|
||||
showToast('Tüm siteler kontrol ediliyor...', 'info');
|
||||
showToast('Tüm siteler ve disk kullanımları kontrol ediliyor...', 'info');
|
||||
|
||||
fetch('/check-all-sites/', {
|
||||
method: 'POST',
|
||||
@ -383,14 +383,27 @@ function checkAllSites() {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast(data.message, 'success');
|
||||
// Sonuçları göster
|
||||
const activeCount = data.results.filter(r => r.status).length;
|
||||
const totalCount = data.results.length;
|
||||
|
||||
// Özet mesaj oluştur
|
||||
const summaryMessage = `
|
||||
<div>
|
||||
<div><strong>Site Kontrolü Tamamlandı</strong></div>
|
||||
<div class="mt-2">${activeCount}/${totalCount} site aktif</div>
|
||||
<div class="small text-muted mt-1">Disk kullanımları güncellendi</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
showToast(summaryMessage, 'success', 5000);
|
||||
setTimeout(() => location.reload(), 2000);
|
||||
} else {
|
||||
showToast(data.message, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('Site kontrol hatası', 'error');
|
||||
showToast('Site ve disk kontrolü hatası', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,24 @@
|
||||
|
||||
{% block content %}
|
||||
<style>
|
||||
/* Alt menü stili */
|
||||
.nav-pills .nav-link {
|
||||
color: #e0e0e0;
|
||||
border-radius: 5px;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link:hover {
|
||||
background-color: rgba(79, 195, 247, 0.1);
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active {
|
||||
background-color: #4fc3f7;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
/* Müşteri kartları */
|
||||
.customer-card {
|
||||
background: #23272b;
|
||||
border: 1px solid #333;
|
||||
@ -31,6 +49,22 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Alt Menü -->
|
||||
<div class="mb-4 border-bottom pb-2">
|
||||
<ul class="nav nav-pills">
|
||||
<li class="nav-item">
|
||||
<a href="{% url 'musteriler' %}" class="nav-link active">
|
||||
<i class="bi bi-person-lines-fill"></i> Müşteri Listesi
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="{% url 'faturalar' %}" class="nav-link text-light">
|
||||
<i class="bi bi-receipt"></i> Faturalar
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h3>Müşteri Yönetimi
|
||||
|
||||
@ -442,16 +442,23 @@
|
||||
<!-- Meta Key Modal -->
|
||||
<div class="modal fade" id="metaKeyModal" tabindex="-1" aria-labelledby="metaKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="metaKeyModalLabel">Site Doğrulama Meta Key</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Kapat"></button>
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header border-secondary">
|
||||
<h5 class="modal-title" id="metaKeyModalLabel">
|
||||
<i class="bi bi-key me-2"></i>Site Doğrulama Meta Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Kapat"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="metaKeyContent">
|
||||
Yükleniyor...
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
<p class="mt-2">Meta key bilgileri yükleniyor...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Kapat</button>
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-outline-light" data-bs-dismiss="modal">Kapat</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -515,7 +522,7 @@ function deleteHost(id) {
|
||||
headers: { 'X-CSRFToken': getCookie('csrftoken') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
.then data => {
|
||||
toastMessage(data.message);
|
||||
if (data.success) setTimeout(() => location.reload(), 1200);
|
||||
});
|
||||
@ -525,7 +532,7 @@ function deleteHost(id) {
|
||||
// Host Düzenle
|
||||
function editHost(id) {
|
||||
fetch(`/get_host/${id}/`)
|
||||
.then(r => r.json())
|
||||
.then r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById('hostId').value = data.host.id;
|
||||
@ -607,7 +614,7 @@ window.deleteProject = function(id) {
|
||||
headers: { 'X-CSRFToken': getCookie('csrftoken') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
.then data => {
|
||||
toastMessage(data.message);
|
||||
if (data.success) {
|
||||
setTimeout(() => location.reload(), 1200);
|
||||
@ -630,7 +637,7 @@ window.backupProject = function(id) {
|
||||
updateProgress(40, 'İşlem devam ediyor...');
|
||||
return r.json();
|
||||
})
|
||||
.then(data => {
|
||||
.then data => {
|
||||
updateProgress(80, 'Tamamlanıyor...');
|
||||
|
||||
setTimeout(() => {
|
||||
@ -711,6 +718,12 @@ window.showLogsByProject = function(projectId) {
|
||||
});
|
||||
}
|
||||
|
||||
// Verify site function - global scope
|
||||
window.verifySite = function(projectId) {
|
||||
checkSiteStatus(projectId);
|
||||
$('#metaKeyModal').modal('hide');
|
||||
}
|
||||
|
||||
// Site durumu kontrol fonksiyonu - global scope
|
||||
window.checkSiteStatus = function(projectId) {
|
||||
// Progress toast'ı başlat
|
||||
@ -737,13 +750,30 @@ window.checkSiteStatus = function(projectId) {
|
||||
hideProgressToast();
|
||||
|
||||
if (data.success) {
|
||||
const statusText = data.status ? '✅ Site Aktif' : '❌ Site Pasif';
|
||||
showToast(statusText, data.status ? 'success' : 'error');
|
||||
const siteStatusText = data.status ? '✅ Site Aktif' : '❌ Site Pasif';
|
||||
const diskStatusText = data.disk_message ? `💾 ${data.disk_message}` : '';
|
||||
|
||||
// Detaylı bilgi içeren bir toast göster
|
||||
const statusHtml = `
|
||||
<div>
|
||||
<div><strong>${siteStatusText}</strong></div>
|
||||
<div class="small text-light-emphasis">${data.site_message}</div>
|
||||
${diskStatusText ? `<div class="mt-2"><strong>${diskStatusText}</strong></div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
showToast(statusHtml, data.status ? 'success' : 'error', 8000);
|
||||
|
||||
// Sayfayı yenile
|
||||
setTimeout(() => location.reload(), 1500);
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
const errorHtml = `
|
||||
<div>
|
||||
<div><strong>❌ Kontrol Başarısız</strong></div>
|
||||
<div class="small text-light-emphasis">${data.message}</div>
|
||||
</div>
|
||||
`;
|
||||
showToast(errorHtml, 'error', 8000);
|
||||
}
|
||||
}, 300);
|
||||
}, 500);
|
||||
@ -751,7 +781,13 @@ window.checkSiteStatus = function(projectId) {
|
||||
.catch(error => {
|
||||
hideProgressToast();
|
||||
console.error('Error:', error);
|
||||
showToast('❌ Kontrol hatası!', 'error');
|
||||
const errorHtml = `
|
||||
<div>
|
||||
<div><strong>❌ Kontrol Hatası</strong></div>
|
||||
<div class="small text-light-emphasis">Sunucu ile iletişim sırasında bir hata oluştu.</div>
|
||||
</div>
|
||||
`;
|
||||
showToast(errorHtml, 'error', 5000);
|
||||
});
|
||||
}
|
||||
|
||||
@ -762,33 +798,47 @@ window.showMetaKey = function(projectId) {
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const content = `
|
||||
<div class="alert alert-info">
|
||||
<h6><i class="bi bi-info-circle"></i> Kullanım Talimatları:</h6>
|
||||
<p>Bu meta tag'ı sitenizin <code><head></code> bölümüne ekleyin:</p>
|
||||
<div class="alert alert-info bg-info bg-opacity-25 text-info mb-3">
|
||||
<h6><i class="bi bi-info-circle"></i> Site Doğrulama</h6>
|
||||
<p>Site sahipliğinizi doğrulamak için aşağıdaki iki yöntemden birini kullanın:</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>Meta Key:</strong></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" value="${data.meta_key}" readonly>
|
||||
<button class="btn btn-outline-secondary" onclick="copyMetaKey('${data.meta_key}')">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
|
||||
<div class="card mb-3 bg-dark border-secondary">
|
||||
<div class="card-header bg-dark border-secondary">
|
||||
<strong>1. Yöntem: HTML Meta Tag</strong> <span class="badge bg-success">Önerilen</span>
|
||||
</div>
|
||||
<div class="card-body bg-dark text-light">
|
||||
<div class="input-group">
|
||||
<textarea class="form-control bg-dark text-light border-secondary" rows="2" readonly id="metaTagText">${data.meta_tag}</textarea>
|
||||
<button class="btn btn-outline-primary" onclick="copyMetaTag()">
|
||||
<i class="bi bi-clipboard"></i> Kopyala
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-light-emphasis mt-2 d-block">Bu meta tag'ı sitenizin <code class="bg-dark text-light"><head></code> bölümüne ekleyin</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>HTML Meta Tag:</strong></label>
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" rows="2" readonly id="metaTagText">${data.meta_tag}</textarea>
|
||||
<button class="btn btn-outline-secondary" onclick="copyMetaTag()">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
<div class="card mb-3 bg-dark border-secondary">
|
||||
<div class="card-header bg-dark border-secondary">
|
||||
<strong>2. Yöntem: HTML Yorum</strong>
|
||||
</div>
|
||||
<div class="card-body bg-dark text-light">
|
||||
<div class="input-group">
|
||||
<textarea class="form-control bg-dark text-light border-secondary" rows="2" readonly>${data.comment_tag}</textarea>
|
||||
<button class="btn btn-outline-primary" onclick="copyToClipboard('${data.comment_tag}')">
|
||||
<i class="bi bi-clipboard"></i> Kopyala
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-light-emphasis mt-2 d-block">Bu yorum satırını HTML sayfanızın herhangi bir yerine ekleyebilirsiniz</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<small><i class="bi bi-exclamation-triangle"></i> Meta tag'ı ekledikten sonra "Site Kontrol" butonuyla doğrulama yapabilirsiniz.</small>
|
||||
<div class="alert alert-warning bg-warning bg-opacity-25 text-warning">
|
||||
<i class="bi bi-exclamation-triangle"></i> Yukarıdaki yöntemlerden birini uyguladıktan sonra
|
||||
<button type="button" class="btn btn-sm btn-outline-light" onclick="verifySite(${data.project_id})">
|
||||
<i class="bi bi-check-circle"></i> Site Kontrol
|
||||
</button>
|
||||
butonuyla doğrulama yapabilirsiniz.
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -924,7 +974,7 @@ if (projectForm) {
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
.then data => {
|
||||
toastMessage(data.message);
|
||||
if (data.success) {
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('addProjectModal'));
|
||||
@ -970,7 +1020,7 @@ if (hostForm) {
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
.then data => {
|
||||
toastMessage(data.message);
|
||||
if (data.success) {
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('addHostModal'));
|
||||
@ -1051,7 +1101,7 @@ if (refreshHostsBtn) {
|
||||
console.log('Response status:', response.status);
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
.then data => {
|
||||
console.log('Response data:', data);
|
||||
hideProgressToast();
|
||||
|
||||
@ -1074,7 +1124,6 @@ if (refreshHostsBtn) {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM yüklendi');
|
||||
});
|
||||
|
||||
</script>
|
||||
</div> <!-- main-content kapanış -->
|
||||
</body>
|
||||
|
||||
@ -12,9 +12,16 @@
|
||||
<small class="text-muted">Tüm hosting projeleri ve yönetim işlemleri</small>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<select id="statusFilter" class="form-select" style="max-width: 180px;">
|
||||
<option value="">Tüm Projeler</option>
|
||||
<option value="active">🟢 Aktif Projeler</option>
|
||||
<option value="inactive">🔴 Pasif Projeler</option>
|
||||
<option value="unknown">⚫ Bilinmeyen Durumlar</option>
|
||||
<option value="no-url">🔘 URL'siz Projeler</option>
|
||||
</select>
|
||||
<input type="text" id="projectSearch" class="form-control" style="max-width: 250px;" placeholder="Proje ara...">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addProjectModal">
|
||||
<i class="bi bi-plus-circle"></i> Yeni Proje
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -28,6 +35,7 @@
|
||||
<th>Proje Bilgileri</th>
|
||||
<th>Klasör & Disk</th>
|
||||
<th>Site Durumu</th>
|
||||
<th>Host Yenileme</th>
|
||||
<th>Son Yedekleme</th>
|
||||
<th class="actions">İşlemler</th>
|
||||
</tr>
|
||||
@ -85,6 +93,21 @@
|
||||
<span class="text-muted">URL tanımlanmamış</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if project.host_renewal_date %}
|
||||
{% if project.host_renewal_date <= today %}
|
||||
<small class="text-danger fw-bold">{{ project.host_renewal_date|date:"d.m.Y" }}</small>
|
||||
<br><span class="badge bg-danger">Süresi Dolmuş</span>
|
||||
{% elif project.host_renewal_date <= warning_date %}
|
||||
<small>{{ project.host_renewal_date|date:"d.m.Y" }}</small>
|
||||
<br><span class="badge bg-warning">Yaklaşıyor</span>
|
||||
{% else %}
|
||||
<small>{{ project.host_renewal_date|date:"d.m.Y" }}</small>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="text-muted">Tarih yok</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if project.last_backup %}
|
||||
<small>{{ project.last_backup|date:"d.m.Y H:i" }}</small>
|
||||
@ -93,13 +116,14 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="actions">
|
||||
<i class="action-icon edit bi bi-pencil" onclick="editProject({{ project.id }})" title="Düzenle"></i>
|
||||
<i class="action-icon delete bi bi-trash" onclick="deleteProject({{ project.id }})" title="Sil"></i>
|
||||
<i class="action-icon backup bi bi-cloud-arrow-up" onclick="backupProject({{ project.id }})" title="Yedekle"></i>
|
||||
<i class="action-icon logs bi bi-journal-text" onclick="showLogsByProject({{ project.id }})" title="Loglar"></i>
|
||||
<i class="action-icon edit bi bi-pencil" onclick="ProjectManager.editProject({{ project.id }})" title="Düzenle"></i>
|
||||
<i class="action-icon delete bi bi-trash" onclick="ProjectManager.deleteProject({{ project.id }})" title="Sil"></i>
|
||||
<i class="action-icon renewal bi bi-calendar-plus" onclick="ProjectManager.renewHost({{ project.id }})" title="Domain Expiration Tarihi Sorgula ve Host Yenile"></i>
|
||||
<i class="action-icon backup bi bi-cloud-arrow-up" onclick="ProjectManager.backupProject({{ project.id }})" title="Yedekle"></i>
|
||||
<i class="action-icon logs bi bi-journal-text" onclick="ProjectManager.showLogsByProject({{ project.id }})" title="Loglar"></i>
|
||||
{% if project.url %}
|
||||
<i class="action-icon site bi bi-globe-americas" onclick="checkSiteStatus({{ project.id }})" title="Site Kontrol"></i>
|
||||
<i class="action-icon meta bi bi-key" onclick="showMetaKey({{ project.id }})" title="Meta Key"></i>
|
||||
<i class="action-icon site bi bi-globe-americas" onclick="ProjectManager.checkSiteStatus({{ project.id }})" title="Site Kontrol"></i>
|
||||
<i class="action-icon meta bi bi-key" onclick="ProjectManager.showMetaKey({{ project.id }})" title="Meta Key"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@ -123,6 +147,7 @@
|
||||
<div class="modal-dialog modal-lg modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<form id="projectForm">
|
||||
<input type="hidden" id="projectId" name="id" value="">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addProjectModalLabel">Yeni Proje Ekle</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Kapat"></button>
|
||||
@ -171,11 +196,16 @@
|
||||
<i class="bi bi-globe me-1"></i>Site Bilgileri
|
||||
</h6>
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<div class="col-md-8">
|
||||
<label for="url" class="form-label">Site URL'i</label>
|
||||
<input type="url" class="form-control" id="url" name="url" placeholder="https://example.com">
|
||||
<input type="text" class="form-control" id="url" name="url" placeholder="https://example.com">
|
||||
<small class="text-muted">Site aktiflik kontrolü için gerekli</small>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="host_renewal_date" class="form-label">Host Yenileme Tarihi</label>
|
||||
<input type="date" class="form-control" id="host_renewal_date" name="host_renewal_date">
|
||||
<small class="text-muted">Hosting paketi yenileme tarihi</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -207,7 +237,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" id="clearLogsBtn" onclick="clearProjectLogs()" style="display: none;">
|
||||
<button type="button" class="btn btn-danger" id="clearLogsBtn" onclick="ProjectManager.clearProjectLogs()" style="display: none;">
|
||||
<i class="bi bi-trash"></i> Logları Temizle
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Kapat</button>
|
||||
@ -219,12 +249,12 @@
|
||||
<!-- Meta Key Modal -->
|
||||
<div class="modal fade" id="metaKeyModal" tabindex="-1" aria-labelledby="metaKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header border-secondary">
|
||||
<h5 class="modal-title" id="metaKeyModalLabel">
|
||||
<i class="bi bi-key me-2"></i>Site Doğrulama Meta Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Kapat"></button>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Kapat"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="metaKeyContent">
|
||||
<div class="text-center">
|
||||
@ -234,28 +264,147 @@
|
||||
<p class="mt-2">Meta key bilgileri yükleniyor...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Kapat</button>
|
||||
<div class="modal-footer border-secondary">
|
||||
<button type="button" class="btn btn-outline-light" data-bs-dismiss="modal">Kapat</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Tüm JavaScript fonksiyonları buradan project_list.html'den kopyalanacak
|
||||
// Proje düzenleme fonksiyonu
|
||||
window.editProject = function(id) {
|
||||
// Version: 2025-08-08-v4-{{ "now"|date:"YmdHis" }} - Fixed function definitions
|
||||
// Ensure DOM is loaded before running scripts
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('DOM loaded, initializing project management functions...');
|
||||
|
||||
// CSRF Token almak için utility fonksiyon
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
const cookies = document.cookie.split(';');
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
const cookie = cookies[i].trim();
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
// Toast bildirim fonksiyonu
|
||||
function showToast(message, type = 'info', duration = 3000) {
|
||||
// Toast container oluştur (eğer yoksa)
|
||||
let toastContainer = document.getElementById('toast-container');
|
||||
if (!toastContainer) {
|
||||
toastContainer = document.createElement('div');
|
||||
toastContainer.id = 'toast-container';
|
||||
toastContainer.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
max-width: 350px;
|
||||
`;
|
||||
document.body.appendChild(toastContainer);
|
||||
}
|
||||
|
||||
// Toast elementi oluştur
|
||||
const toast = document.createElement('div');
|
||||
const bgClass = type === 'success' ? 'bg-success' :
|
||||
type === 'error' ? 'bg-danger' :
|
||||
type === 'warning' ? 'bg-warning' : 'bg-info';
|
||||
|
||||
toast.className = `alert ${bgClass} text-white mb-2`;
|
||||
toast.style.cssText = `
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transition: all 0.3s ease;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
||||
`;
|
||||
toast.innerHTML = message;
|
||||
|
||||
// Toast'u container'a ekle
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
// Animasyonla göster
|
||||
setTimeout(() => {
|
||||
toast.style.opacity = '1';
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// Belirtilen süre sonra kaldır
|
||||
setTimeout(() => {
|
||||
toast.style.opacity = '0';
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
// ============= PROJE YÖNETİM FONKSİYONLARI =============
|
||||
|
||||
// Proje düzenleme fonksiyonu
|
||||
function editProject(id) {
|
||||
console.log('editProject called with ID:', id);
|
||||
fetch(`/get-project-details/${id}/`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
console.log('Project details response:', data);
|
||||
if (data.success) {
|
||||
document.getElementById('projectId').value = id;
|
||||
document.getElementById('name').value = data.project.name;
|
||||
document.getElementById('folder_name').value = data.project.folder_name;
|
||||
|
||||
// URL değerini ayarla - mevcut URL'yi olduğu gibi göster
|
||||
const urlValue = data.project.url || '';
|
||||
document.getElementById('url').value = urlValue;
|
||||
|
||||
// Host yenileme tarihini ayarla
|
||||
const renewalDate = data.project.host_renewal_date || '';
|
||||
document.getElementById('host_renewal_date').value = renewalDate;
|
||||
|
||||
document.getElementById('ssh_credential').value = data.project.ssh_credential_id || '';
|
||||
document.getElementById('customer').value = data.project.customer_id || '';
|
||||
document.getElementById('addProjectModalLabel').innerText = 'Proje Düzenle';
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('addProjectModal'));
|
||||
modal.show();
|
||||
} else {
|
||||
showToast('❌ Proje bilgisi alınamadı!', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('editProject error:', error);
|
||||
showToast('❌ Proje bilgisi alınırken hata oluştu!', 'error');
|
||||
});
|
||||
}
|
||||
function editProject(id) {
|
||||
console.log('editProject called with ID:', id);
|
||||
fetch(`/get-project-details/${id}/`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
.then data => {
|
||||
console.log('Project details response:', data);
|
||||
if (data.success) {
|
||||
document.getElementById('projectId').value = id;
|
||||
document.getElementById('name').value = data.project.name;
|
||||
document.getElementById('folder_name').value = data.project.folder_name;
|
||||
document.getElementById('url').value = data.project.url || '';
|
||||
|
||||
// URL değerini ayarla - mevcut URL'yi olduğu gibi göster
|
||||
const urlValue = data.project.url || '';
|
||||
document.getElementById('url').value = urlValue;
|
||||
|
||||
// Host yenileme tarihini ayarla
|
||||
const renewalDate = data.project.host_renewal_date || '';
|
||||
document.getElementById('host_renewal_date').value = renewalDate;
|
||||
|
||||
document.getElementById('ssh_credential').value = data.project.ssh_credential_id || '';
|
||||
document.getElementById('customer').value = data.project.customer_id || '';
|
||||
|
||||
document.getElementById('addProjectModalLabel').innerText = 'Proje Düzenle';
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('addProjectModal'));
|
||||
@ -265,234 +414,329 @@ window.editProject = function(id) {
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('editProject error:', error);
|
||||
showToast('❌ Proje bilgisi alınırken hata oluştu!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Proje Sil
|
||||
window.deleteProject = function(id) {
|
||||
if (confirm('Projeyi silmek istediğinize emin misiniz?')) {
|
||||
fetch(`/delete_project/${id}/`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRFToken': getCookie('csrftoken') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('✅ Proje başarıyla silindi', 'success');
|
||||
setTimeout(() => location.reload(), 1200);
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Proje Sil
|
||||
function deleteProject(id) {
|
||||
if (confirm('Projeyi silmek istediğinize emin misiniz?')) {
|
||||
fetch(`/delete_project/${id}/`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRFToken': getCookie('csrftoken') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('✅ Proje başarıyla silindi', 'success');
|
||||
setTimeout(() => location.reload(), 1200);
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Proje Yedekle
|
||||
window.backupProject = function(id) {
|
||||
if (confirm('Projeyi yedeklemek istiyor musunuz?')) {
|
||||
showToast('🔄 Yedekleme başlatılıyor...', 'info');
|
||||
|
||||
fetch(`/backup-project/${id}/`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRFToken': getCookie('csrftoken') }
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('✅ Yedekleme başarılı', 'success');
|
||||
setTimeout(() => {
|
||||
window.showLogsByProject(id);
|
||||
}, 800);
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('❌ Yedekleme hatası!', 'error');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Log görüntüleme
|
||||
window.showLogsByProject = function(projectId) {
|
||||
window.currentProjectId = projectId;
|
||||
function backupProject(id) {
|
||||
showToast('🔄 Proje yedekleniyor...', 'info');
|
||||
|
||||
fetch(`/project/${projectId}/backup-logs/`)
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
let html = '';
|
||||
let hasLogs = false;
|
||||
|
||||
if (data.success && data.logs.length > 0) {
|
||||
hasLogs = true;
|
||||
html = '<div class="log-list">';
|
||||
data.logs.forEach(function(log) {
|
||||
let statusBadge = log.status ?
|
||||
'<span class="badge bg-success me-2"><i class="bi bi-check-circle"></i> Başarılı</span>' :
|
||||
'<span class="badge bg-danger me-2"><i class="bi bi-x-circle"></i> Hata</span>';
|
||||
|
||||
let typeIcon = '';
|
||||
if (log.log_type === 'backup') {
|
||||
typeIcon = '<i class="bi bi-cloud-arrow-up text-warning me-2"></i>';
|
||||
} else if (log.log_type === 'command') {
|
||||
typeIcon = '<i class="bi bi-terminal text-info me-2"></i>';
|
||||
}
|
||||
|
||||
html += `
|
||||
<div class="log-entry mb-3 p-3" style="background: rgba(255,255,255,0.05); border-radius: 8px; border-left: 3px solid ${log.status ? '#28a745' : '#dc3545'};">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<div>${statusBadge}${typeIcon}<strong>${log.command}</strong></div>
|
||||
<small class="text-muted">${log.created_at}</small>
|
||||
</div>
|
||||
<div class="log-output" style="font-family: monospace; font-size: 0.9em; color: #bdbdbd;">
|
||||
${log.output.replace(/\n/g, '<br>')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
html += '</div>';
|
||||
} else {
|
||||
html = `
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-journal-text" style="font-size: 2rem; color: #6c757d;"></i>
|
||||
<p class="text-muted mt-2">Bu projeye ait log bulunamadı</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
document.getElementById('logsContent').innerHTML = html;
|
||||
|
||||
const clearBtn = document.getElementById('clearLogsBtn');
|
||||
clearBtn.style.display = hasLogs ? 'inline-block' : 'none';
|
||||
|
||||
const logsModal = new bootstrap.Modal(document.getElementById('logsModal'));
|
||||
logsModal.show();
|
||||
});
|
||||
}
|
||||
|
||||
// Site durumu kontrol
|
||||
window.checkSiteStatus = function(projectId) {
|
||||
showToast('🔄 Site kontrol ediliyor...', 'info');
|
||||
|
||||
fetch(`/project/${projectId}/check-site/`, {
|
||||
fetch(`/backup-project/${id}/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken'),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const statusText = data.status ? '✅ Site Aktif' : '❌ Site Pasif';
|
||||
showToast(statusText, data.status ? 'success' : 'error');
|
||||
setTimeout(() => location.reload(), 1500);
|
||||
showToast('✅ Proje başarıyla yedeklendi!', 'success');
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('❌ Kontrol hatası!', 'error');
|
||||
console.error('Backup error:', error);
|
||||
showToast('❌ Yedekleme sırasında hata oluştu!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Meta key göster
|
||||
window.showMetaKey = function(projectId) {
|
||||
fetch(`/project/${projectId}/meta-key/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const content = `
|
||||
<div class="alert alert-info">
|
||||
<h6><i class="bi bi-info-circle"></i> Kullanım Talimatları:</h6>
|
||||
<p>Bu meta tag'ı sitenizin <code><head></code> bölümüne ekleyin:</p>
|
||||
</div>
|
||||
// Log görüntüleme
|
||||
function showLogsByProject(id) {
|
||||
// Modal'ı aç
|
||||
const logsModal = new bootstrap.Modal(document.getElementById('logsModal'));
|
||||
logsModal.show();
|
||||
|
||||
// Loading durumunu göster
|
||||
document.getElementById('logsContent').innerHTML = `
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loglar yükleniyor...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Clear logs butonunu gizle
|
||||
document.getElementById('clearLogsBtn').style.display = 'none';
|
||||
|
||||
fetch(`/project/${id}/backup-logs/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
console.log('Logs:', data.logs);
|
||||
|
||||
if (data.logs.length > 0) {
|
||||
let logsHtml = '<div class="logs-container">';
|
||||
|
||||
data.logs.forEach(log => {
|
||||
const statusIcon = log.status === 'success' ?
|
||||
'<i class="bi bi-check-circle-fill text-success me-2"></i>' :
|
||||
'<i class="bi bi-x-circle-fill text-danger me-2"></i>';
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>Meta Key:</strong></label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" value="${data.meta_key}" readonly>
|
||||
<button class="btn btn-outline-secondary" onclick="copyToClipboard('${data.meta_key}')">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
const logTypeIcon = log.log_type === 'backup' ?
|
||||
'<i class="bi bi-cloud-arrow-up me-1"></i>' :
|
||||
'<i class="bi bi-terminal me-1"></i>';
|
||||
|
||||
logsHtml += `
|
||||
<div class="card mb-3 ${log.status === 'success' ? 'border-success' : 'border-danger'}">
|
||||
<div class="card-header d-flex justify-content-between align-items-center py-2">
|
||||
<div>
|
||||
${statusIcon}
|
||||
${logTypeIcon}
|
||||
<small class="text-muted">${log.created_at}</small>
|
||||
</div>
|
||||
<span class="badge ${log.status === 'success' ? 'bg-success' : 'bg-danger'}">${log.status}</span>
|
||||
</div>
|
||||
<div class="card-body py-2">
|
||||
<p class="mb-2"><strong>Komut:</strong></p>
|
||||
<code class="d-block bg-dark text-light p-2 rounded mb-2">${log.command}</code>
|
||||
|
||||
<p class="mb-2"><strong>Çıktı:</strong></p>
|
||||
<pre class="bg-light p-2 rounded text-dark" style="max-height: 200px; overflow-y: auto; font-size: 0.85rem;">${log.output}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>HTML Meta Tag:</strong></label>
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" rows="2" readonly>${data.meta_tag}</textarea>
|
||||
<button class="btn btn-outline-secondary" onclick="copyToClipboard('${data.meta_tag}')">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<small><i class="bi bi-exclamation-triangle"></i> Meta tag'ı ekledikten sonra "Site Kontrol" butonuyla doğrulama yapabilirsiniz.</small>
|
||||
`;
|
||||
});
|
||||
|
||||
logsHtml += '</div>';
|
||||
document.getElementById('logsContent').innerHTML = logsHtml;
|
||||
|
||||
// Clear logs butonunu göster
|
||||
document.getElementById('clearLogsBtn').style.display = 'inline-block';
|
||||
} else {
|
||||
document.getElementById('logsContent').innerHTML = `
|
||||
<div class="text-center text-muted py-4">
|
||||
<i class="bi bi-journal-text" style="font-size: 3rem;"></i>
|
||||
<h5 class="mt-3">Bu proje için henüz log kaydı bulunmuyor</h5>
|
||||
<p class="text-muted">Yedekleme veya site kontrol işlemleri yapıldığında loglar burada görünecektir.</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('metaKeyContent').innerHTML = content;
|
||||
const modal = new bootstrap.Modal(document.getElementById('metaKeyModal'));
|
||||
modal.show();
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('❌ Meta key alınırken hata oluştu!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Clipboard'a kopyala
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
showToast('📋 Panoya kopyalandı!', 'success');
|
||||
}).catch(err => {
|
||||
showToast('❌ Kopyalama hatası!', 'error');
|
||||
} else {
|
||||
document.getElementById('logsContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
${data.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Logs error:', error);
|
||||
document.getElementById('logsContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
Loglar yüklenirken hata oluştu!
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Log temizleme
|
||||
function clearProjectLogs() {
|
||||
if (!window.currentProjectId) {
|
||||
showToast('Proje ID bulunamadı!', 'error');
|
||||
return;
|
||||
}
|
||||
// Site durumu kontrol
|
||||
function checkSiteStatus(id) {
|
||||
showToast('🔄 Site durumu kontrol ediliyor...', 'info');
|
||||
|
||||
if (!confirm('Bu projenin tüm loglarını silmek istediğinizden emin misiniz?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/project/${window.currentProjectId}/clear-logs/`, {
|
||||
fetch(`/project/${id}/check-site/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken'),
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('logsModal'));
|
||||
if (modal) modal.hide();
|
||||
|
||||
showToast(`✅ ${data.deleted_count} log kaydı silindi`, 'success');
|
||||
window.currentProjectId = null;
|
||||
showToast('✅ Site kontrol tamamlandı!', 'success');
|
||||
setTimeout(() => window.location.reload(), 1500);
|
||||
} else {
|
||||
showToast(`❌ ${data.message || 'Log silme işlemi başarısız!'}`, 'error');
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showToast('❌ Log silme sırasında bir hata oluştu!', 'error');
|
||||
console.error('Site check error:', error);
|
||||
showToast('❌ Site kontrol sırasında hata oluştu!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Meta Key Göster
|
||||
function showMetaKey(id) {
|
||||
// Modal'ı aç
|
||||
const metaKeyModal = new bootstrap.Modal(document.getElementById('metaKeyModal'));
|
||||
metaKeyModal.show();
|
||||
|
||||
// Loading durumunu göster
|
||||
document.getElementById('metaKeyContent').innerHTML = `
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Yükleniyor...</span>
|
||||
</div>
|
||||
<p class="mt-2">Meta key bilgileri yükleniyor...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
fetch(`/project/${id}/meta-key/`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
console.log('Meta key:', data);
|
||||
|
||||
let metaKeyHtml = `
|
||||
<div class="mb-4">
|
||||
<h6 class="text-warning mb-3">
|
||||
<i class="bi bi-info-circle me-2"></i>Site Doğrulama Talimatları
|
||||
</h6>
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-2">Sitenizin doğrulanması için aşağıdaki meta tag'i HTML'inizin <head> bölümüne ekleyin:</p>
|
||||
<ol class="mb-0">
|
||||
<li>Site yönetici paneline giriş yapın</li>
|
||||
<li>Tema düzenleyicisini açın (header.php veya index.html)</li>
|
||||
<li>Aşağıdaki meta tag'i <head> bölümüne ekleyin</li>
|
||||
<li>Değişiklikleri kaydedin</li>
|
||||
<li>"Site Doğrula" butonuna tıklayın</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label text-warning fw-bold">Meta Verification Tag:</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control bg-dark text-light border-secondary"
|
||||
value='${data.meta_key}' readonly id="metaKeyInput">
|
||||
<button class="btn btn-outline-info" type="button" onclick="ProjectManager.copyToClipboard('${data.meta_key}')">>
|
||||
<i class="bi bi-clipboard"></i> Kopyala
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted">Bu meta tag'i sitenizin <head> bölümüne ekleyin</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<h6 class="text-warning mb-3">
|
||||
<i class="bi bi-check-circle me-2"></i>Doğrulama İşlemi
|
||||
</h6>
|
||||
<div class="d-grid">
|
||||
<button class="btn btn-success btn-lg" onclick="ProjectManager.verifySite(${id})">>
|
||||
<i class="bi bi-shield-check me-2"></i>Site Doğrula
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted d-block text-center mt-2">
|
||||
Meta tag'i ekledikten sonra bu butona tıklayın
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Önemli:</strong> Meta tag'i eklemeden önce doğrulama yapmayın.
|
||||
Tag eklendikten sonra 2-3 dakika bekleyip doğrulama yapın.
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('metaKeyContent').innerHTML = metaKeyHtml;
|
||||
} else {
|
||||
document.getElementById('metaKeyContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
${data.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Meta key error:', error);
|
||||
document.getElementById('metaKeyContent').innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
Meta key alınırken hata oluştu!
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Clipboard'a kopyala
|
||||
function copyToClipboard(text) {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
showToast('✅ Panoya kopyalandı!', 'success');
|
||||
}).catch(err => {
|
||||
console.error('Copy error:', err);
|
||||
showToast('❌ Kopyalama hatası!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Site doğrula
|
||||
function verifySite(projectId) {
|
||||
showToast('🔄 Site doğrulama tamamlandı!', 'success');
|
||||
|
||||
fetch(`/project/${projectId}/check-site/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken'),
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('✅ Site doğrulama tamamlandı!', 'success');
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Site doğrulama hatası:', error);
|
||||
showToast('❌ Site doğrulama hatası!', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// Proje loglarını temizle
|
||||
function clearProjectLogs() {
|
||||
if (confirm('Tüm proje loglarını temizlemek istediğinize emin misiniz?')) {
|
||||
showToast('🔄 Loglar temizleniyor...', 'info');
|
||||
|
||||
fetch('/logs/clear/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken'),
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('✅ Loglar temizlendi!', 'success');
|
||||
setTimeout(() => window.location.reload(), 1500);
|
||||
} else {
|
||||
showToast(`❌ ${data.message}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Clear logs error:', error);
|
||||
showToast('❌ Log temizleme hatası!', 'error');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Proje Form Submit
|
||||
document.getElementById('projectForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const id = document.getElementById('projectId').value;
|
||||
const url = id ? `/update-project/${id}/` : '/project/create/';
|
||||
const formData = new FormData(this);
|
||||
@ -515,40 +759,122 @@ document.getElementById('projectForm').addEventListener('submit', function(e) {
|
||||
});
|
||||
});
|
||||
|
||||
// Proje Arama
|
||||
document.getElementById('projectSearch').addEventListener('keyup', function() {
|
||||
const searchTerm = this.value.toLowerCase().trim();
|
||||
// Durum Filtresi
|
||||
document.getElementById('statusFilter').addEventListener('change', function() {
|
||||
const filterValue = this.value;
|
||||
const projectRows = document.querySelectorAll('tbody tr');
|
||||
|
||||
if (searchTerm.length < 2) {
|
||||
projectRows.forEach(row => {
|
||||
if (row.cells.length > 1) {
|
||||
row.style.display = '';
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
projectRows.forEach(row => {
|
||||
if (row.cells.length > 1) {
|
||||
const projectInfo = row.cells[1].textContent.toLowerCase();
|
||||
const folderInfo = row.cells[2].textContent.toLowerCase();
|
||||
const siteInfo = row.cells[3].textContent.toLowerCase();
|
||||
|
||||
if (projectInfo.includes(searchTerm) || folderInfo.includes(searchTerm) || siteInfo.includes(searchTerm)) {
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.style.display = 'none';
|
||||
const siteStatusCell = row.cells[3]; // Site Durumu sütunu
|
||||
let shouldShow = false;
|
||||
|
||||
if (filterValue === '') {
|
||||
// Tüm projeler
|
||||
shouldShow = true;
|
||||
} else if (filterValue === 'active') {
|
||||
// Aktif projeler - success badge'i olanlar
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-success') !== null;
|
||||
} else if (filterValue === 'inactive') {
|
||||
// Pasif projeler - danger badge'i olanlar
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-danger') !== null;
|
||||
} else if (filterValue === 'unknown') {
|
||||
// Bilinmeyen durum - secondary badge'i olanlar
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-secondary') !== null;
|
||||
} else if (filterValue === 'no-url') {
|
||||
// URL'siz projeler - "URL tanımlanmamış" yazısı olanlar
|
||||
shouldShow = siteStatusCell.textContent.includes('URL tanımlanmamış');
|
||||
}
|
||||
|
||||
row.style.display = shouldShow ? '' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Filtreleme sonucunda gösterilen proje sayısını güncelle
|
||||
updateProjectCount();
|
||||
});
|
||||
|
||||
// Proje sayısını güncelleme fonksiyonu
|
||||
function updateProjectCount() {
|
||||
const visibleRows = document.querySelectorAll('tbody tr[style=""], tbody tr:not([style])');
|
||||
const totalRows = document.querySelectorAll('tbody tr').length;
|
||||
|
||||
// Eğer empty state row varsa onu sayma
|
||||
const actualVisibleRows = Array.from(visibleRows).filter(row => row.cells.length > 1);
|
||||
const actualTotalRows = Array.from(document.querySelectorAll('tbody tr')).filter(row => row.cells.length > 1);
|
||||
|
||||
// Başlığı güncelle
|
||||
const headerText = document.querySelector('h3');
|
||||
const originalText = headerText.textContent.split(' (')[0]; // Mevcut sayı bilgisini temizle
|
||||
|
||||
if (actualTotalRows.length > 0) {
|
||||
if (actualVisibleRows.length !== actualTotalRows.length) {
|
||||
headerText.innerHTML = `<i class="bi bi-folder-fill me-2"></i>Projeler (${actualVisibleRows.length}/${actualTotalRows.length})`;
|
||||
} else {
|
||||
headerText.innerHTML = `<i class="bi bi-folder-fill me-2"></i>Projeler (${actualTotalRows.length})`;
|
||||
}
|
||||
} else {
|
||||
headerText.innerHTML = `<i class="bi bi-folder-fill me-2"></i>Projeler`;
|
||||
}
|
||||
}
|
||||
|
||||
// Proje Arama (güncellenmiş versiyon - filtreleme ile uyumlu)
|
||||
document.getElementById('projectSearch').addEventListener('keyup', function() {
|
||||
const searchTerm = this.value.toLowerCase().trim();
|
||||
const statusFilter = document.getElementById('statusFilter').value;
|
||||
const projectRows = document.querySelectorAll('tbody tr');
|
||||
|
||||
projectRows.forEach(row => {
|
||||
if (row.cells.length > 1) {
|
||||
let shouldShow = true;
|
||||
|
||||
// Önce arama terimine göre kontrol et
|
||||
if (searchTerm.length >= 2) {
|
||||
const projectInfo = row.cells[1].textContent.toLowerCase();
|
||||
const folderInfo = row.cells[2].textContent.toLowerCase();
|
||||
const siteInfo = row.cells[3].textContent.toLowerCase();
|
||||
|
||||
shouldShow = projectInfo.includes(searchTerm) ||
|
||||
folderInfo.includes(searchTerm) ||
|
||||
siteInfo.includes(searchTerm);
|
||||
}
|
||||
|
||||
// Sonra durum filtresine göre kontrol et
|
||||
if (shouldShow && statusFilter !== '') {
|
||||
const siteStatusCell = row.cells[3];
|
||||
|
||||
if (statusFilter === 'active') {
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-success') !== null;
|
||||
} else if (statusFilter === 'inactive') {
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-danger') !== null;
|
||||
} else if (statusFilter === 'unknown') {
|
||||
shouldShow = siteStatusCell.querySelector('.badge.bg-secondary') !== null;
|
||||
} else if (statusFilter === 'no-url') {
|
||||
shouldShow = siteStatusCell.textContent.includes('URL tanımlanmamış');
|
||||
}
|
||||
}
|
||||
|
||||
row.style.display = shouldShow ? '' : 'none';
|
||||
}
|
||||
});
|
||||
|
||||
// Proje sayısını güncelle
|
||||
updateProjectCount();
|
||||
});
|
||||
|
||||
// Proje Arama (eski kod - kaldırıldı)
|
||||
|
||||
// Modal reset
|
||||
document.getElementById('addProjectModal').addEventListener('hidden.bs.modal', function () {
|
||||
document.getElementById('projectForm').reset();
|
||||
document.getElementById('projectId').value = '';
|
||||
document.getElementById('addProjectModalLabel').textContent = 'Yeni Proje Ekle';
|
||||
});
|
||||
|
||||
// Sayfa yüklendiğinde proje sayısını göster
|
||||
updateProjectCount();
|
||||
|
||||
}); // DOMContentLoaded end
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user