This commit is contained in:
ilkeral
2025-08-08 07:24:25 +03:00
parent 342f1314c7
commit f4ee7a2d0b
29 changed files with 5189 additions and 1140 deletions

View File

@ -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>&lt;head&gt;</code> bölümüne ekleyin:</p>
</div>
// Log görüntüleme
function showLogsByProject(id) {
// Modal'ı
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'ı
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 &lt;head&gt; 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 &lt;head&gt; 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 &lt;head&gt; 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 %}