Files
hostpanel/ssh_manager/views.py
ilkeral f4ee7a2d0b yeni
2025-08-08 07:24:25 +03:00

3158 lines
120 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.views.decorators.http import require_http_methods
from django.db import models
from django.db.models import Q
from django.utils import timezone
from .backup import job
from .models import SSHCredential, Project, SSHLog, Customer, Backup
from .ssh_client import SSHManager
from django.http import JsonResponse, HttpResponse
from django.http import HttpResponseNotAllowed
import logging
from django.core.files.storage import FileSystemStorage
import os
import json
from django.views.decorators.csrf import csrf_exempt # Ekleyin
from django.contrib.auth.decorators import login_required
from django.core.exceptions import ValidationError
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
import zipfile
import shutil
from datetime import datetime
from django.conf import settings
import tempfile # Ekleyin
from io import BytesIO
from django.utils import timezone
from django.views.decorators.http import require_GET
from django.views.decorators.csrf import ensure_csrf_cookie
# Logger oluştur
logger = logging.getLogger(__name__)
# Utils import
try:
from utils.whois_tools import get_domain_expiration_date
WHOIS_TOOLS_AVAILABLE = True
except ImportError as e:
WHOIS_TOOLS_AVAILABLE = False
# Logger henüz tanımlanmamış olabilir, print kullan
print(f"WHOIS tools import hatası: {e}")
@require_GET
def get_host(request, host_id):
from .models import SSHCredential
try:
host = SSHCredential.objects.get(id=host_id)
return JsonResponse({
'success': True,
'host': {
'id': host.id,
'hostname': host.hostname,
'username': host.username,
'password': '', # Güvenlik için boş bırak
'port': host.port,
'base_path': host.base_path,
'created_at': host.created_at.strftime('%Y-%m-%d %H:%M:%S') if host.created_at else '',
'is_online': host.is_online,
'last_check': host.last_check.strftime('%Y-%m-%d %H:%M:%S') if host.last_check else ''
}
})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
@ensure_csrf_cookie
def dashboard(request):
"""Dashboard sayfası - özet ve istatistikler"""
projects = Project.objects.all().select_related('customer', 'ssh_credential')
ssh_credentials = SSHCredential.objects.all()
customers = Customer.objects.filter(is_active=True)
recent_logs = SSHLog.objects.all().order_by('-created_at')[:10]
# İstatistikler
active_sites_count = projects.filter(is_site_active=True).count()
online_hosts_count = ssh_credentials.filter(connection_status='connected').count()
recent_backups = projects.filter(last_backup__isnull=False).order_by('-last_backup')[:6]
context = {
'projects': projects,
'ssh_credentials': ssh_credentials,
'customers': customers,
'recent_logs': recent_logs,
'active_sites_count': active_sites_count,
'online_hosts_count': online_hosts_count,
'recent_backups': recent_backups,
}
return render(request, 'ssh_manager/dashboard.html', context)
# Bağlantı kontrolü yapıldı mı kontrolü için global değişken
_connection_checked = False
@ensure_csrf_cookie
def project_list(request):
"""Projeler sayfası - detaylı proje listesi"""
projects = Project.objects.all().select_related('customer', 'ssh_credential')
ssh_credentials = SSHCredential.objects.all()
customers = Customer.objects.filter(is_active=True).order_by('name')
ssh_logs = SSHLog.objects.all() # Log kayıtlarını al
context = {
'projects': projects,
'ssh_credentials': ssh_credentials,
'customers': customers,
'ssh_logs': ssh_logs, # Log kayıtlarını context'e ekle
}
return render(request, 'ssh_manager/projeler.html', context)
def projeler(request):
"""Projeler sayfası için wrapper - project_list'i çağırır"""
return project_list(request)
def update_all_hosts_status():
"""Tüm hostların bağlantı durumunu ve disk kullanım bilgisini güncelle"""
print("update_all_hosts_status fonksiyonu çağrıldı")
ssh_credentials = SSHCredential.objects.all()
print(f"Toplam {ssh_credentials.count()} host bulundu")
for credential in ssh_credentials:
print(f"Host kontrol ediliyor: {credential.hostname}")
ssh_manager = SSHManager(credential)
try:
# Bağlantı durumunu kontrol et
is_online = ssh_manager.check_connection()
print(f"{credential.hostname} bağlantı durumu: {is_online}")
credential.is_online = is_online
# Disk kullanım bilgisini al (sadece online ise)
if is_online:
disk_usage_info = ssh_manager.get_disk_usage()
print(f"{credential.hostname} disk bilgisi: {disk_usage_info}")
if disk_usage_info:
# Dictionary'yi string'e çevir (görüntüleme için)
credential.disk_usage = f"{disk_usage_info['used']} / {disk_usage_info['total']} ({disk_usage_info['usage_percent']}%)"
print(f"{credential.hostname} disk kullanımı kaydedildi: {credential.disk_usage}")
else:
credential.disk_usage = None
print(f"{credential.hostname} disk bilgisi alınamadı")
else:
credential.disk_usage = None
print(f"{credential.hostname} offline, disk bilgisi null")
credential.save()
print(f"{credential.hostname} veritabanına kaydedildi")
except Exception as e:
# Hata durumunda offline olarak işaretle
credential.is_online = False
credential.disk_usage = None
credential.save()
print(f"Host {credential.hostname} güncelleme hatası: {e}")
finally:
ssh_manager.close()
print("update_all_hosts_status tamamlandı")
@require_http_methods(["GET", "POST"])
def create_project(request):
if request.method == 'POST':
name = request.POST.get('name')
folder_name = request.POST.get('folder_name')
ssh_credential_id = request.POST.get('ssh_credential')
url = request.POST.get('url', '').strip()
ssh_manager = None
try:
ssh_credential = SSHCredential.objects.get(id=ssh_credential_id)
# SSH bağlantısı kur ve kontrol et
ssh_manager = SSHManager(ssh_credential)
connection_status = ssh_manager.check_connection()
if not connection_status:
return JsonResponse({
'success': False,
'message': 'SSH bağlantısı kurulamadı! Lütfen bağlantı bilgilerini kontrol edin.'
})
# Proje klasör adının benzersiz olup olmadığını kontrol et
if Project.objects.filter(folder_name=folder_name, ssh_credential=ssh_credential).exists():
return JsonResponse({
'success': False,
'message': f'"{folder_name}" klasör adı bu sunucuda zaten kullanılıyor!'
})
# Klasörün var olup olmadığını kontrol et
check_cmd = f'test -d "{ssh_credential.base_path}/{folder_name}" && echo "exists" || echo "not exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
if stdout.strip() == "exists":
return JsonResponse({
'success': False,
'message': f'"{folder_name}" klasörü sunucuda zaten mevcut!'
})
# Proje oluştur
customer_id = request.POST.get('customer')
customer = None
if customer_id:
try:
customer = Customer.objects.get(id=customer_id)
except Customer.DoesNotExist:
pass
project = Project(
name=name,
folder_name=folder_name,
ssh_credential=ssh_credential,
customer=customer,
url=url if url else None
)
try:
project.full_clean()
except ValidationError as e:
return JsonResponse({
'success': False,
'message': f'Validasyon hatası: {e}'
})
# Önce projeyi kaydet
project.save()
# Klasör oluştur ve izinleri ayarla
commands = [
f'mkdir -p "{project.get_full_path()}"',
f'chown -R www-data:www-data "{project.get_full_path()}"',
f'chmod -R 755 "{project.get_full_path()}"',
]
for cmd in commands:
stdout, stderr, status = ssh_manager.execute_command(cmd)
if not status:
# Hata durumunda projeyi sil
ssh_manager.execute_command(f'rm -rf "{project.get_full_path()}"')
project.delete()
return JsonResponse({
'success': False,
'message': f'Klasör işlemleri sırasında hata: {stderr}'
})
# Log oluştur
SSHLog.objects.create(
ssh_credential=ssh_credential,
log_type='project',
command=f'Proje oluşturuldu: {name}',
output=f'Klasör: {project.get_full_path()}',
status=True
)
return JsonResponse({
'success': True,
'message': f'Proje başarıyla oluşturuldu: {project.get_full_path()}'
})
except SSHCredential.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Geçersiz SSH bağlantısı!'
})
except Exception as e:
logger.exception("Proje oluşturma hatası")
return JsonResponse({
'success': False,
'message': f'Beklenmeyen bir hata oluştu: {str(e)}'
})
finally:
if ssh_manager:
ssh_manager.close()
# GET isteği için SSH credentials listesini JSON olarak dön
ssh_credentials = SSHCredential.objects.all()
return JsonResponse({
'ssh_credentials': list(ssh_credentials.values('id', 'hostname', 'username', 'base_path'))
})
def view_logs(request, ssh_credential_id=None):
if ssh_credential_id:
# Belirli bir SSH bağlantısının loglarını göster
credential = SSHCredential.objects.get(id=ssh_credential_id)
logs = SSHLog.objects.filter(ssh_credential=credential)
context = {'credential': credential, 'logs': logs}
else:
# Tüm logları göster
logs = SSHLog.objects.all()
context = {'logs': logs}
return render(request, 'ssh_manager/view_logs.html', context)
@require_http_methods(["POST"])
def check_connection(request, project_id):
try:
project = Project.objects.get(id=project_id)
ssh_manager = SSHManager(project.ssh_credential)
if ssh_manager.check_connection():
messages.success(request, 'Bağlantı başarılı')
else:
messages.error(request, 'Bağlantı başarısız')
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return render(request, 'ssh_manager/messages.html')
return redirect('project_list')
except Exception as e:
messages.error(request, str(e))
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
return render(request, 'ssh_manager/messages.html')
return redirect('project_list')
def check_folder_permissions(request):
# Klasör işlemleriyle ilgili logları getir
folder_logs = SSHLog.objects.filter(
log_type='folder'
).order_by('created_at')
# Bağlantı loglarını getir
connection_logs = SSHLog.objects.filter(
log_type='connection'
).order_by('created_at')
context = {
'folder_logs': folder_logs,
'connection_logs': connection_logs
}
return render(request, 'ssh_manager/check_permissions.html', context)
@require_http_methods(["POST"])
def upload_project_zip(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
if 'zip_file' not in request.FILES:
return JsonResponse({
'success': False,
'message': 'Dosya seçilmedi'
})
zip_file = request.FILES['zip_file']
# Dosya uzantısı kontrolü
allowed_extensions = ['.zip', '.txt']
file_extension = os.path.splitext(zip_file.name)[1].lower()
if file_extension not in allowed_extensions:
return JsonResponse({
'success': False,
'message': 'Geçersiz dosya formatı. Sadece .zip ve .txt dosyaları yüklenebilir.'
})
# SSH bağlantısı
ssh_manager = project.ssh_credential.get_manager()
try:
# Bağlantı kontrolü
if not ssh_manager.check_connection():
return JsonResponse({
'success': False,
'message': 'SSH bağlantısı kurulamadı'
})
# Dosyayı geçici olarak kaydet
fs = FileSystemStorage(location='temp_uploads')
filename = fs.save(zip_file.name, zip_file)
file_path = fs.path(filename)
try:
# SFTP ile dosyayı yükle
sftp = ssh_manager.client.open_sftp()
remote_path = f"{project.get_full_path()}/{zip_file.name}"
sftp.put(file_path, remote_path)
sftp.close()
# Zip dosyasını
if file_extension == '.zip':
unzip_cmd = f'cd {project.get_full_path()} && unzip -o "{zip_file.name}" && rm "{zip_file.name}"'
stdout, stderr, status = ssh_manager.execute_command(unzip_cmd)
if not status:
return JsonResponse({
'success': False,
'message': f'Zip dosyasıılamadı: {stderr}'
})
# Log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=f'Dosya başarıyla yüklendi: {zip_file.name}',
status=True
)
return JsonResponse({
'success': True,
'message': 'Dosya başarıyla yüklendi'
})
finally:
# Geçici dosyayı sil
if os.path.exists(file_path):
os.remove(file_path)
finally:
ssh_manager.close()
except Exception as e:
logger.exception("Dosya yükleme hatası")
return JsonResponse({
'success': False,
'message': f'Beklenmeyen bir hata oluştu: {str(e)}'
})
@require_http_methods(["POST"])
@csrf_exempt
def delete_project(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Önce proje klasörünün varlığını kontrol et
check_cmd = f'test -d "{project.get_full_path()}" && echo "exists" || echo "not exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
if stdout.strip() != "exists":
project.delete()
return JsonResponse({'success': True, 'message': 'Proje veritabanından silindi (klasör zaten silinmiş)'})
# Klasör varsa silme işlemini başlat
delete_cmd = f'rm -rf "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(delete_cmd)
if status:
project.delete()
return JsonResponse({'success': True, 'message': 'Proje başarıyla silindi'})
else:
return JsonResponse({'success': False, 'message': f'Proje silinirken hata oluştu: {stderr}'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Silme işlemi sırasında hata: {str(e)}'})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Proje bulunamadı'})
@require_http_methods(["POST"])
def setup_venv(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
logger.info(f"Setting up virtual environment for project: {project.name}")
# Virtual environment kurulumu
cmd = f'''
cd {project.get_full_path()} && \
python3 -m venv venv && \
sudo chown -R www-data:www-data venv && \
sudo chmod -R 755 venv
'''
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command="Virtual Environment Kurulumu",
output=f"Başarılı: {stdout}",
status=True
)
return JsonResponse({
'status': 'success',
'message': 'Virtual environment başarıyla oluşturuldu'
})
else:
error_msg = f'Virtual environment oluşturulamadı: {stderr}'
logger.error(error_msg)
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command="Virtual Environment Kurulumu",
output=f"Hata: {stderr}",
status=False
)
return JsonResponse({
'status': 'error',
'message': error_msg
}, status=500)
except Exception as e:
logger.exception("Error in setup_venv")
return JsonResponse({
'status': 'error',
'message': str(e)
}, status=500)
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def download_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# req.txt dosyasını kontrol et ve içeriğini al
check_cmd = f'test -f "{project.get_full_path()}/req.txt" && cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
if status:
response = HttpResponse(stdout, content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename="{project.folder_name}_req.txt"'
return response
else:
return HttpResponse('req.txt dosyası bulunamadı.', status=404)
except Exception as e:
return HttpResponse(f'Hata: {str(e)}', status=500)
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def check_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Tam yolu logla
full_path = project.get_full_path()
logger.info(f"Proje bilgileri:")
logger.info(f"Proje adı: {project.name}")
logger.info(f"Klasör adı: {project.folder_name}")
logger.info(f"Tam yol: {full_path}")
# Önce dosyanın varlığını kontrol et
check_cmd = f'test -f "{full_path}/req.txt" && echo "exists"'
check_stdout, check_stderr, check_status = ssh_manager.execute_command(check_cmd)
logger.info(f"Dosya kontrol komutu: {check_cmd}")
logger.info(f"Kontrol çıktısı: {check_stdout}")
if check_status and check_stdout.strip() == "exists":
# Dosya varsa içeriğini oku
cat_cmd = f'cat "{full_path}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(cat_cmd)
logger.info(f"Okuma komutu: {cat_cmd}")
logger.info(f"Okuma çıktısı: {stdout}")
logger.info(f"Okuma hatası: {stderr}")
if status and stdout.strip():
return JsonResponse({
'success': True,
'content': stdout
})
else:
error_msg = 'req.txt dosyası boş' if status else f'req.txt dosyası okunamadı: {stderr}'
logger.error(error_msg)
return JsonResponse({
'success': False,
'message': error_msg
})
else:
error_msg = 'req.txt dosyası bulunamadı'
logger.error(error_msg)
return JsonResponse({
'success': False,
'message': error_msg
})
except Exception as e:
logger.exception("req.txt kontrol hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def download_req_file(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Dosya içeriğini doğrudan oku
command = f'cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(command)
if not status:
return JsonResponse({
'success': False,
'message': 'req.txt dosyası bulunamadı'
})
# Dosya içeriği varsa, indirme yanıtı oluştur
response = HttpResponse(stdout, content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename="{project.folder_name}_req.txt"'
# Log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='download',
command='Requirements İndirme',
output=f'req.txt dosyası indirildi: {project.folder_name}',
status=True
)
return response
finally:
ssh_manager.close()
except Exception as e:
logger.exception("Requirements indirme hatası")
return JsonResponse({
'success': False,
'message': f'Dosya indirme hatası: {str(e)}'
})
def create_system_log(message, status=True, log_type='system', ssh_credential=None, command=None, output=None):
"""Sistem logu oluştur ve JSON olarak dön"""
log = SSHLog.objects.create(
ssh_credential=ssh_credential,
log_type=log_type,
command=command or 'Sistem',
output=output or message,
status=status
)
return {
'id': log.id,
'timestamp': log.created_at.strftime('%H:%M:%S'),
'message': message,
'command': command,
'output': output,
'status': status
}
@require_http_methods(["POST"])
def clear_logs(request):
try:
# Tüm logları sil
SSHLog.objects.all().delete()
# Log oluştur
SSHLog.objects.create(
ssh_credential=SSHCredential.objects.first(),
log_type='command',
command='Clear Logs',
output='Tüm log kayıtları temizlendi',
status=True
)
return JsonResponse({
'success': True,
'message': 'Loglar başarıyla temizlendi'
})
except Exception as e:
logger.exception("Log temizleme hatası")
return JsonResponse({
'success': False,
'message': f'Loglar temizlenirken hata oluştu: {str(e)}'
}, status=500)
@require_http_methods(["GET"])
def check_venv(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# venv klasörünün varlığını kontrol et
check_cmd = f'test -d "{project.get_full_path()}/venv" && echo "exists" || echo "not exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
exists = stdout.strip() == "exists"
log_data = create_system_log(
message=f'Virtual environment kontrolü: {"Mevcut" if exists else "Mevcut değil"}',
status=True,
ssh_credential=project.ssh_credential,
command='Venv Kontrolü',
output=f'Proje: {project.name}'
)
return JsonResponse({
'success': True,
'exists': exists,
'log': log_data
})
except Exception as e:
logger.exception("Venv kontrol hatası")
log_data = create_system_log(
message=f'Virtual environment kontrol hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Venv Kontrolü'
)
return JsonResponse({
'success': False,
'exists': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def install_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Venv'i aktive et ve pip install çalıştır
cmd = f'''
cd {project.get_full_path()} && \
source venv/bin/activate && \
if [ -f "req.txt" ]; then
pip install -r req.txt
else
echo "req.txt dosyası bulunamadı"
exit 1
fi
'''
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
log_data = create_system_log(
message='Paketler başarıyla kuruldu',
status=True,
ssh_credential=project.ssh_credential,
command='Pip Install',
output=stdout
)
else:
log_data = create_system_log(
message='Paket kurulumu başarısız oldu',
status=False,
ssh_credential=project.ssh_credential,
command='Pip Install',
output=stderr
)
return JsonResponse({
'success': status,
'log': log_data
})
except Exception as e:
logger.exception("Paket kurulum hatası")
log_data = create_system_log(
message=f'Paket kurulum hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Pip Install'
)
return JsonResponse({
'success': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def check_folder_empty(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Klasördeki dosya ve klasörleri listele
cmd = f'ls -A "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(cmd)
is_empty = not stdout.strip() # Boş string ise klasör boştur
if not is_empty:
files = stdout.strip().split('\n')
log_data = create_system_log(
message=f'Klasör içeriği kontrol edildi: {len(files)} öğe mevcut',
status=True,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü',
output=f'Mevcut dosyalar: {", ".join(files)}'
)
else:
log_data = create_system_log(
message='Klasör boş',
status=True,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü'
)
return JsonResponse({
'success': True,
'is_empty': is_empty,
'files': stdout.strip().split('\n') if not is_empty else [],
'log': log_data
})
except Exception as e:
logger.exception("Klasör kontrol hatası")
log_data = create_system_log(
message=f'Klasör kontrol hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü'
)
return JsonResponse({
'success': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@login_required
def list_project_files(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = SSHManager(project.ssh_credential)
if not ssh_manager.check_connection():
return JsonResponse({
'success': False,
'message': 'SSH bağlantısı kurulamadı!'
})
# Proje klasöründeki dosyaları listele
cmd = f'ls -la "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(cmd)
if not status:
return JsonResponse({
'success': False,
'message': f'Dosya listesi alınamadı: {stderr}'
})
# ls -la çıktısını parse et
files = []
for line in stdout.splitlines()[1:]: # İlk satırı atla (toplam)
if line.strip():
parts = line.split()
if len(parts) >= 9:
permissions = parts[0]
size = parts[4]
date = ' '.join(parts[5:8])
name = ' '.join(parts[8:])
files.append({
'name': name,
'permissions': permissions,
'size': size,
'date': date
})
return JsonResponse({
'success': True,
'files': files
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı!'
})
except Exception as e:
logger.exception("Dosya listeleme hatası")
return JsonResponse({
'success': False,
'message': f'Beklenmeyen bir hata oluştu: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@login_required
def upload_project_files(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = SSHManager(project.ssh_credential)
try:
success, ssh_message = ssh_manager.upload_project_zip(project, request.FILES['files'])
if success:
# Başarılı durumda log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=ssh_message, # SSH'den dönen detaylı başarı mesajı
status=True
)
# Kullanıcıya genel başarı mesajı
return JsonResponse({
'success': True,
'message': 'Dosyalar başarıyla yüklendi'
})
else:
# Hata durumunda detaylı log oluştur
logger.error(ssh_message) # SSH hatasını direkt logla
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=ssh_message, # SSH'den dönen detaylı hata mesajı
status=False
)
# Kullanıcıya genel hata mesajı
return JsonResponse({
'success': False,
'message': 'Dosya yükleme işlemi başarısız oldu'
})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
})
except Exception as e:
# Beklenmeyen hataları detaylı şekilde logla
logger.exception('Beklenmeyen bir hata oluştu')
SSHLog.objects.create(
ssh_credential=project.ssh_credential if 'project' in locals() else None,
log_type='upload',
command='Dosya Yükleme',
output=str(e), # Ham hata mesajı
status=False
)
# Kullanıcıya genel hata mesajı
return JsonResponse({
'success': False,
'message': 'Beklenmeyen bir hata oluştu'
})
@require_http_methods(["POST"])
def get_latest_logs(request):
logs = SSHLog.objects.all().order_by('-created_at')[:50] # Son 50 log
log_data = [{
'created_at': log.created_at.strftime('%d.%m.%Y %H:%M:%S'),
'log_type_display': log.get_log_type_display(),
'command': log.command,
'output': log.output,
'status': log.status
} for log in logs]
return JsonResponse({'logs': log_data})
@require_http_methods(["POST"])
def restart_supervisor(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Supervisor'ı yeniden başlat
cmd = f'sudo supervisorctl restart {project.folder_name}'
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
log_data = create_system_log(
message='Supervisor başarıyla yeniden başlatıldı',
status=True,
ssh_credential=project.ssh_credential,
command='Supervisor Restart',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Uygulama başarıyla yeniden başlatıldı',
'log': log_data
})
else:
log_data = create_system_log(
message='Supervisor yeniden başlatılamadı',
status=False,
ssh_credential=project.ssh_credential,
command='Supervisor Restart',
output=stderr
)
return JsonResponse({
'success': False,
'message': 'Uygulama yeniden başlatılamadı',
'log': log_data
})
except Exception as e:
logger.exception("Supervisor restart hatası")
log_data = create_system_log(
message=f'Supervisor restart hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Supervisor Restart'
)
return JsonResponse({
'success': False,
'message': str(e),
'log': log_data
})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
})
@require_http_methods(["POST"])
def update_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# JSON verilerini al
data = json.loads(request.body)
new_content = data.get('content', '')
# Yeni içeriği req.txt dosyasına yaz
write_cmd = f'echo "{new_content}" > "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(write_cmd)
if status:
log_data = create_system_log(
message='Requirements içeriği güncellendi',
status=True,
ssh_credential=project.ssh_credential,
command='Requirements Güncelleme',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Requirements içeriği başarıyla güncellendi',
'log': log_data
})
else:
log_data = create_system_log(
message='Requirements güncellenirken hata oluştu',
status=False,
ssh_credential=project.ssh_credential,
command='Requirements Güncelleme',
output=stderr
)
return JsonResponse({
'success': False,
'message': f'Requirements güncellenirken hata oluştu: {stderr}',
'log': log_data
})
except Exception as e:
logger.exception("Requirements güncelleme hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def delete_requirement_line(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# JSON verilerini al
data = json.loads(request.body)
line_index = int(data.get('line_index', -1)) # int'e çevir
# Mevcut içeriği oku
read_cmd = f'cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(read_cmd)
if not status:
return JsonResponse({
'success': False,
'message': 'Requirements dosyası okunamadı'
})
# Satırları ayır ve belirtilen satırı sil
lines = [line for line in stdout.strip().split('\n') if line.strip()] # Boş satırları filtrele
if 0 <= line_index < len(lines):
deleted_line = lines.pop(line_index)
new_content = '\n'.join(lines)
# Yeni içeriği dosyaya yaz
write_cmd = f"echo '{new_content}' > '{project.get_full_path()}/req.txt'"
stdout, stderr, status = ssh_manager.execute_command(write_cmd)
if status:
log_data = create_system_log(
message=f'Requirements satırı silindi: {deleted_line}',
status=True,
ssh_credential=project.ssh_credential,
command='Requirements Satır Silme',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Satır başarıyla silindi',
'content': new_content,
'log': log_data
})
return JsonResponse({
'success': False,
'message': 'Satır silinemedi'
})
except Exception as e:
logger.exception("Requirements satır silme hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def refresh_project(request, project_id):
ssh_manager = None
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Proje klasörünü kontrol et
project_path = project.get_full_path()
# Disk kullanımını hesapla (du komutu ile)
du_cmd = f"du -sh {project_path}"
stdout, stderr, status = ssh_manager.execute_command(du_cmd)
if status:
# du çıktısını parse et (örn: "156M /path/to/folder")
disk_usage = stdout.split()[0]
project.disk_usage = disk_usage
project.save()
# Requirements dosyasını kontrol et (req.txt)
stdout, stderr, status = ssh_manager.execute_command(f"ls {project_path}/req.txt")
has_requirements = status
# Requirements içeriğini al
if has_requirements:
stdout, stderr, status = ssh_manager.execute_command(f"cat {project_path}/req.txt")
req_content = stdout if status else ""
else:
req_content = ""
# Log oluştur
log_data = create_system_log(
message='Proje bilgileri güncellendi',
status=True,
ssh_credential=project.ssh_credential,
command='Proje Güncelleme',
output=f"Requirements durumu: {'Mevcut' if has_requirements else 'Mevcut değil'}"
)
return JsonResponse({
'success': True,
'project_info': {
'base_path': project.ssh_credential.base_path,
'folder_name': project.folder_name,
'disk_usage': project.disk_usage or '0B'
},
'has_requirements': has_requirements,
'requirements_content': req_content,
'message': 'Proje başarıyla güncellendi',
'log': log_data
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
}, status=404)
except Exception as e:
logger.exception("Proje güncelleme hatası")
log_data = create_system_log(
message=f'Proje güncellenirken hata oluştu: {str(e)}',
status=False,
ssh_credential=project.ssh_credential if 'project' in locals() else None,
command='Proje Güncelleme'
)
return JsonResponse({
'success': False,
'message': str(e),
'log': log_data
}, status=500)
finally:
if ssh_manager:
ssh_manager.close()
# @require_http_methods(["POST"])
# def backup_projects(request):
# logger.info("====== BACKUP İŞLEMİ BAŞLIYOR ======")
#
# try:
# ssh_credential = SSHCredential.objects.first()
# if not ssh_credential:
# raise ValueError("SSH bağlantısı bulunamadı")
#
# # Başlangıç logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup İşlemi',
# output='Yedekleme işlemi başlatıldı',
# status=True
# )
#
# # Google Drive bağlantı logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Google Drive Bağlantısı',
# output='Google Drive API bağlantısı kuruluyor...',
# status=True
# )
#
# credentials = service_account.Credentials.from_service_account_info(
# settings.GOOGLE_DRIVE_CREDENTIALS,
# scopes=['https://www.googleapis.com/auth/drive.file']
# )
# drive_service = build('drive', 'v3', credentials=credentials)
#
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Google Drive Bağlantısı',
# output='Google Drive API bağlantısı başarıyla kuruldu',
# status=True
# )
#
# ssh_manager = ssh_credential.get_manager()
#
# try:
# for project in Project.objects.all():
# # Proje yedekleme başlangıç logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Proje: {project.name}',
# output=f'{project.name} projesi yedekleme işlemi başladı',
# status=True
# )
#
# backup_name = f'{project.folder_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.zip'
# project_path = project.get_full_path()
#
# # Zip işlemi
# zip_cmd = f'''
# cd {project_path}/.. && \
# zip -9 -r "{project.folder_name}.zip" "{project.folder_name}" && \
# mv "{project.folder_name}.zip" "/tmp/{backup_name}"
# '''
# logger.info(f"Zip komutu çalıştırılıyor: {zip_cmd}")
#
# stdout, stderr, status = ssh_manager.execute_command(zip_cmd)
#
# if not status:
# error_msg = f"{project.name} için zip oluşturma hatası:\nStdout: {stdout}\nStderr: {stderr}"
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Zip Hatası: {project.name}',
# output=error_msg,
# status=False
# )
# continue
#
# # Zip dosyası boyutunu ve başarı durumunu logla
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Zip: {project.name}',
# output=f'{project.name} projesi için zip dosyası oluşturuldu\n{stdout}',
# status=True
# )
#
# # Dosya tipini kontrol et
# check_cmd = f'file "/tmp/{backup_name}"'
# stdout, stderr, status = ssh_manager.execute_command(check_cmd)
# logger.info(f"Dosya tipi kontrolü: {stdout}")
#
# # Dosya boyutunu kontrol et
# size_cmd = f'ls -lh "/tmp/{backup_name}"'
# size_out, size_err, size_status = ssh_manager.execute_command(size_cmd)
# logger.info(f"Dosya boyutu: {size_out}")
#
# if not status or 'Zip archive data' not in stdout:
# error_msg = f"Oluşturulan dosya bir zip arşivi değil: {stdout}"
# logger.error(error_msg)
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Kontrol: {project.name}',
# output=error_msg,
# status=False
# )
# continue
#
# # Google Drive yükleme işlemi...
# # ... (mevcut Drive yükleme kodu devam eder)
#
# # Tamamlanma logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup İşlemi',
# output='Tüm projelerin yedekleme işlemi başarıyla tamamlandı',
# status=True
# )
#
# return JsonResponse({
# 'success': True,
# 'message': 'Yedekleme işlemi tamamlandı!'
# })
#
# finally:
# ssh_manager.close()
#
# except Exception as e:
# error_msg = f"Yedekleme sırasında hata oluştu: {str(e)}"
# if 'ssh_credential' in locals():
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup Hatası',
# output=error_msg,
# status=False
# )
# return JsonResponse({
# 'success': False,
# 'message': error_msg
# })
@require_http_methods(["POST"])
def backup_project(request, project_id):
import traceback
import sys
import platform
import tempfile
# Log system information
logger.info(f"===== BACKUP DEBUG INFO =====")
logger.info(f"Backup request for project ID: {project_id}")
logger.info(f"Platform: {platform.system()} {platform.release()}")
logger.info(f"Python version: {platform.python_version()}")
logger.info(f"Temp directory: {tempfile.gettempdir()}")
logger.info(f"Working directory: {os.getcwd()}")
try:
logger.info(f"Getting project with ID: {project_id}")
project = get_object_or_404(Project, id=project_id)
folder_name = project.folder_name
# Path normalization for Linux/Windows compatibility
base_path = project.ssh_credential.base_path or ""
base_path = base_path.rstrip('/')
calisma_dizini = f"{base_path}/{folder_name}" if base_path else folder_name
logger.info(f"Project: {project.name}, Folder: {folder_name}, Path: {calisma_dizini}")
if not folder_name:
return JsonResponse({
'success': False,
'message': 'Klasör adı bulunamadı'
})
try:
# SSH bağlantısı oluştur ve hata ayıklama bilgisi ekle
logger.info(f"Establishing SSH connection to {project.ssh_credential}")
try:
ssh_manager = project.ssh_credential.get_manager()
logger.info(f"SSH connection established successfully")
except Exception as ssh_err:
logger.error(f"SSH connection error: {str(ssh_err)}")
return JsonResponse({
'success': False,
'message': f'SSH bağlantı hatası: {str(ssh_err)}'
})
# SSH üzerinde basit bir test yap
logger.info(f"Testing basic SSH functionality")
test_cmd = "echo 'SSH_TEST_OK'"
test_stdout, test_stderr, test_status = ssh_manager.execute_command(test_cmd)
logger.info(f"SSH test result: status={test_status}, output={test_stdout.strip()}")
if not test_status:
logger.error(f"SSH basic test failed: {test_stderr}")
return JsonResponse({
'success': False,
'message': f'SSH temel fonksiyonalite testi başarısız: {test_stderr}'
})
# Özel karakterleri escape et
safe_path = calisma_dizini.replace('"', '\\"')
logger.info(f"Checking directory existence: {safe_path}")
# Klasörün varlığını kontrol et
check_cmd = f'test -d "{safe_path}" && echo "exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
logger.info(f"Directory check result: status={status}, output={stdout.strip()}, error={stderr.strip()}")
if not status or stdout.strip() != "exists":
# Eğer klasör yoksa üst dizini listele (debug için)
parent_dir = os.path.dirname(safe_path)
if parent_dir:
logger.info(f"Source directory not found, listing parent dir: {parent_dir}")
list_cmd = f'ls -la "{parent_dir}"'
list_stdout, list_stderr, list_status = ssh_manager.execute_command(list_cmd)
logger.info(f"Parent directory contents: {list_stdout}")
return JsonResponse({
'success': False,
'message': f'Yedeklenecek klasör bulunamadı: {calisma_dizini}'
})
# Backup kaydını oluştur (başlangıç)
backup_record = Backup.objects.create(
project=project,
backup_type='manual',
status='running',
notes=f'Manuel yedekleme başlatıldı: {calisma_dizini}'
)
# Backup işlemini başlat
logger.info(f"Starting backup job: folder={folder_name}, path={calisma_dizini}, project_id={project_id}")
try:
result = job(folder_name, calisma_dizini, project_id)
logger.info(f"Backup job result: {result}")
except Exception as backup_err:
logger.error(f"Exception during backup job: {str(backup_err)}")
logger.error(f"Traceback: {''.join(traceback.format_exception(*sys.exc_info()))}")
# Backup kaydını güncelle
backup_record.status = 'failed'
backup_record.end_time = timezone.now()
backup_record.error_message = f"Uygulama hatası: {str(backup_err)}"
backup_record.save()
raise Exception(f"Yedekleme işlemi sırasında hata: {str(backup_err)}")
if not result.get('success'):
error_msg = result.get('message', 'Backup işlemi başarısız oldu')
logger.error(f"Backup job failed: {error_msg}")
# Backup kaydını başarısız olarak güncelle
backup_record.status = 'failed'
backup_record.end_time = timezone.now()
backup_record.error_message = error_msg
backup_record.save()
raise Exception(error_msg)
# Backup başarılı - kaydı güncelle
backup_record.status = 'completed'
backup_record.end_time = timezone.now()
backup_record.notes = f'Yedekleme başarıyla tamamlandı: {calisma_dizini}'
# Backup detaylarını ekle (eğer result'ta varsa)
if result.get('file_path'):
backup_record.file_path = result.get('file_path')
if result.get('file_size'):
# Sayı olduğundan emin ol
try:
file_size = int(result.get('file_size'))
backup_record.file_size = file_size # Integer olarak sakla (BigIntegerField için uygun)
except (ValueError, TypeError):
# Sayıya çevrilemiyorsa string olarak sakla
try:
# Sayı formatındaki stringleri temizle ve dönüştür
file_size_str = str(result.get('file_size')).strip()
file_size_cleaned = ''.join(c for c in file_size_str if c.isdigit())
if file_size_cleaned:
backup_record.file_size = int(file_size_cleaned)
else:
backup_record.file_size = 0
except:
backup_record.file_size = 0
backup_record.save()
# Backup tarihini güncelle
project.last_backup = timezone.now()
project.save()
# Log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='backup',
command=f'Backup: {folder_name}',
output=f'Backup başarıyla tamamlandı. Dizin: {calisma_dizini}',
status=True
)
return JsonResponse({
'success': True,
'message': 'Yedekleme işlemi başarıyla tamamlandı'
})
except Exception as e:
# Get full exception details
exc_type, exc_value, exc_traceback = sys.exc_info()
error_details = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
error_msg = str(e)
logger.error(f"Exception in backup process: {error_msg}")
logger.error(f"Detailed traceback:\n{error_details}")
if 'NoSuchBucket' in error_msg:
error_msg = 'Backup bucket\'ı bulunamadı. Sistem yöneticinize başvurun.'
# Eğer backup kaydı oluşturulduysa ama başarısız olduysa güncelle
if 'backup_record' in locals():
backup_record.status = 'failed'
backup_record.end_time = timezone.now()
backup_record.error_message = f"{error_msg}\n\nTeknik detaylar: {error_details[:500]}..."
backup_record.save()
# Hata logu oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='backup',
command=f'Backup Error: {folder_name}',
output=f'Hata: {error_msg}',
status=False
)
logger.exception(f"Backup error for project {project_id}")
return JsonResponse({
'success': False,
'message': f'Yedekleme işlemi başarısız: {error_msg}'
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
def get_project_details(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
data = {
'success': True,
'project': {
'name': project.name,
'folder_name': project.folder_name,
'url': project.url,
'ssh_credential_id': project.ssh_credential.id if project.ssh_credential else '',
'customer_id': project.customer.id if project.customer else '',
'last_backup': project.last_backup.strftime('%d.%m.%Y %H:%M') if project.last_backup else None,
'disk_usage': project.disk_usage or '0B',
'host_renewal_date': project.host_renewal_date.strftime('%Y-%m-%d') if project.host_renewal_date else None,
}
}
return JsonResponse(data)
except Exception as e:
return JsonResponse({'success': False, 'message': 'Proje detayları alınırken bir hata oluştu.'})
@require_http_methods(["POST"])
def delete_host(request, host_id):
try:
host = SSHCredential.objects.get(id=host_id)
host.delete()
return JsonResponse({'success': True, 'message': 'Host başarıyla silindi'})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': 'Host silinirken bir hata oluştu'})
@require_http_methods(["POST"])
def update_host(request, host_id):
try:
host = SSHCredential.objects.get(id=host_id)
host.hostname = request.POST.get('hostname')
host.username = request.POST.get('username')
password = request.POST.get('password')
if password:
host.password = password
host.port = request.POST.get('port')
host.base_path = request.POST.get('base_path')
host.full_clean()
host.save()
return JsonResponse({'success': True, 'message': 'Host başarıyla güncellendi'})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
except ValidationError as e:
return JsonResponse({'success': False, 'message': str(e)})
except Exception as e:
return JsonResponse({'success': False, 'message': 'Host güncellenirken bir hata oluştu'})
@require_http_methods(["GET"])
def project_backup_logs(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
# Hem backup hem de site kontrol loglarını getir
logs = SSHLog.objects.filter(
ssh_credential=project.ssh_credential,
).filter(
models.Q(log_type='backup', command__icontains=project.folder_name) |
models.Q(log_type='command', command__icontains=project.name)
).order_by('-created_at') # En yeni önce
log_data = [
{
'created_at': log.created_at.strftime('%d.%m.%Y %H:%M:%S'),
'command': log.command,
'output': log.output,
'status': log.status,
'log_type': log.log_type
}
for log in logs
]
return JsonResponse({'success': True, 'logs': log_data})
except Exception as e:
return JsonResponse({'success': False, 'message': str(e)})
@require_http_methods(["POST"])
def update_project(request, project_id):
try:
project = Project.objects.get(id=project_id)
project.name = request.POST.get('name')
project.folder_name = request.POST.get('folder_name')
project.url = request.POST.get('url', '')
# SSH Credential güncelleme
ssh_credential_id = request.POST.get('ssh_credential')
if ssh_credential_id:
try:
ssh_credential = SSHCredential.objects.get(id=ssh_credential_id)
project.ssh_credential = ssh_credential
except SSHCredential.DoesNotExist:
pass
# Customer güncelleme
customer_id = request.POST.get('customer')
if customer_id:
try:
customer = Customer.objects.get(id=customer_id)
project.customer = customer
except Customer.DoesNotExist:
pass
else:
project.customer = None
# Model validation
project.full_clean()
project.save()
return JsonResponse({
'success': True,
'message': 'Proje başarıyla güncellendi'
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
}, status=404)
except ValidationError as e:
return JsonResponse({
'success': False,
'message': str(e)
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'message': 'Proje güncellenirken bir hata oluştu'
}, status=500)
@require_http_methods(["POST"])
def clear_project_logs(request, project_id):
"""Belirtilen projenin tüm loglarını sil"""
try:
project = get_object_or_404(Project, id=project_id)
# Bu projeye ait tüm logları sil - hem backup hem de site kontrol logları
deleted_count = SSHLog.objects.filter(
ssh_credential=project.ssh_credential
).filter(
# Backup logları veya site kontrol logları
Q(log_type='backup', command__icontains=project.folder_name) |
Q(log_type='command', command__icontains=project.name)
).delete()[0]
return JsonResponse({
'success': True,
'message': f'{deleted_count} log kaydı silindi',
'deleted_count': deleted_count
})
except Exception as e:
return JsonResponse({
'success': False,
'message': f'Log silme hatası: {str(e)}'
}, status=500)
@require_http_methods(["POST"])
def check_site_status_view(request, project_id):
"""Tek projenin site durumunu kontrol et"""
try:
project = get_object_or_404(Project, id=project_id)
from .utils import check_site_status, check_disk_usage
from .models import SSHLog
# Site kontrol işlemini başlat ve log kaydı yap
log_entry = SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command=f"Site kontrol: {project.url} (Proje: {project.name})",
output="Site kontrol işlemi başlatıldı...",
status=False # Başlangıçta False, sonra güncellenecek
)
try:
# 1. Site durumunu kontrol et (meta key doğrulaması ile)
site_status, site_message = check_site_status(project)
# 2. Disk kullanımını kontrol et (ayrı bir işlem olarak)
disk_status, disk_message = check_disk_usage(project)
# Sonuçları birleştir
combined_message = f"Site Kontrolü: {site_message}\nDisk Kontrolü: {disk_message}"
# Log kaydını güncelle
log_entry.output = combined_message
log_entry.status = site_status # Site durumuna göre log durumunu belirle
log_entry.save()
# Host bağlantı durumunu güncelle
if project.ssh_credential:
ssh_manager = SSHManager(project.ssh_credential)
try:
# Bağlantı durumunu kontrol et
is_online = ssh_manager.check_connection()
project.ssh_credential.is_online = is_online
project.ssh_credential.save()
except Exception as e:
# Hata durumunda offline olarak işaretle
project.ssh_credential.is_online = False
project.ssh_credential.save()
print(f"Host bağlantı durumu güncelleme hatası: {e}")
finally:
ssh_manager.close()
return JsonResponse({
'success': True,
'status': site_status, # Site durumunu döndür
'message': combined_message,
'site_message': site_message,
'disk_message': disk_message,
'is_active': project.is_site_active,
'disk_usage': project.disk_usage,
'last_check': project.last_site_check.strftime('%d.%m.%Y %H:%M') if project.last_site_check else None
})
except Exception as e:
# Hata durumunda log kaydını güncelle
log_entry.output = f"Kontrol hatası: {str(e)}"
log_entry.status = False
log_entry.save()
raise e
except Exception as e:
return JsonResponse({
'success': False,
'message': f'Kontrol hatası: {str(e)}'
}, status=500)
def check_all_sites_view(request):
"""Tüm projelerin site durumunu kontrol et ve sonuçları döndür"""
try:
from .utils import check_all_sites
# Tüm siteleri kontrol et
results = check_all_sites()
# Sonuçları JSON formatına dönüştür
data = {
'success': True,
'results': [
{
'project_id': result['project'].id,
'project_name': result['project'].name,
'url': result['project'].url,
'status': result['status'],
'site_message': result['site_message'],
'disk_status': result['disk_status'],
'disk_message': result['disk_message'],
'combined_message': result['combined_message']
} for result in results
]
}
return JsonResponse(data)
except Exception as e:
return JsonResponse({'success': False, 'message': f'Tüm siteleri kontrol ederken bir hata oluştu: {str(e)}'})
@require_http_methods(["GET"])
def get_domain_expiration(request):
url = request.GET.get("url")
# Basit console output ekleyelim
print(f"=== Domain expiration request başladı ===")
print(f"URL: {url}")
print(f"WHOIS_TOOLS_AVAILABLE: {WHOIS_TOOLS_AVAILABLE}")
if not url:
print("URL parametresi eksik")
return JsonResponse({"error": "URL parametresi eksik."}, status=400)
try:
if not WHOIS_TOOLS_AVAILABLE:
print("WHOIS tools modülü mevcut değil")
return JsonResponse({
"error": "WHOIS servis şu anda kullanılamıyor.",
"debug": "WHOIS_TOOLS_AVAILABLE = False"
}, status=503)
print("WHOIS tools import test başlıyor...")
# Test amaçlı import kontrolü
try:
from utils.whois_tools import test_whois_function
test_result = test_whois_function()
print(f"Test fonksiyonu sonucu: {test_result}")
except Exception as test_e:
print(f"Test fonksiyonu import hatası: {test_e}")
return JsonResponse({
"error": f"Test hatası: {str(test_e)}",
"debug": f"Import error: {test_e}"
}, status=500)
print("get_domain_expiration_date çağrılıyor...")
expiration_date = get_domain_expiration_date(url)
print(f"get_domain_expiration_date sonucu: {expiration_date}")
if expiration_date:
print(f"Başarılı sonuç döndürülüyor: {expiration_date}")
return JsonResponse({"domain_expiration": expiration_date})
else:
print("Expiration bilgisi None döndü")
return JsonResponse({"error": "Expiration bilgisi alınamadı."}, status=500)
except Exception as e:
print(f"=== GENEL HATA ===")
print(f"Hata: {str(e)}")
print(f"Hata tipi: {type(e)}")
import traceback
print(f"Traceback:")
traceback.print_exc()
return JsonResponse({
"error": f"Domain sorgusu sırasında hata oluştu: {str(e)}",
"debug": f"Exception type: {type(e).__name__}"
}, status=500)
@require_http_methods(["GET"])
def get_all_logs(request):
"""Tüm sistem loglarını getir (İşlem Geçmişi için)"""
try:
# Tüm backup ve site kontrol loglarını al
backup_logs = SSHLog.objects.filter(log_type='backup').select_related('ssh_credential')
command_logs = SSHLog.objects.filter(log_type='command').select_related('ssh_credential')
all_logs = []
# Backup loglarını ekle
for log in backup_logs:
all_logs.append({
'id': log.id,
'created_at': log.created_at.isoformat(),
'log_type': log.log_type,
'command': log.command,
'output': log.output,
'status': log.status,
'hostname': log.ssh_credential.hostname if log.ssh_credential else 'Bilinmiyor'
})
# Komut loglarını ekle
for log in command_logs:
all_logs.append({
'id': log.id,
'created_at': log.created_at.isoformat(),
'log_type': log.log_type,
'command': log.command,
'output': log.output,
'status': log.status,
'hostname': log.ssh_credential.hostname if log.ssh_credential else 'Bilinmiyor'
})
# Tarihe göre sırala (en yeni önce)
all_logs.sort(key=lambda x: x['created_at'], reverse=True)
return JsonResponse({
'success': True,
'logs': all_logs,
'total_count': len(all_logs)
})
except Exception as e:
print(f"get_all_logs hatası: {e}")
return JsonResponse({
'success': False,
'message': f'Log yükleme hatası: {str(e)}',
'logs': []
})
def islem_gecmisi(request):
"""İşlem Geçmişi sayfası"""
# Tüm logları al
backup_logs = SSHLog.objects.filter(log_type='backup').select_related('ssh_credential')
command_logs = SSHLog.objects.filter(log_type='command').select_related('ssh_credential')
# Logları birleştir ve tarihe göre sırala
all_logs = list(backup_logs) + list(command_logs)
all_logs.sort(key=lambda x: x.created_at, reverse=True)
context = {
'logs': all_logs,
'page_title': 'İşlem Geçmişi',
'active_menu': 'islem_gecmisi'
}
return render(request, 'ssh_manager/islem_gecmisi.html', context)
def host_yonetimi(request):
"""Host Yönetimi sayfası"""
ssh_credentials = SSHCredential.objects.all()
context = {
'ssh_credentials': ssh_credentials,
'page_title': 'Host Yönetimi',
'active_menu': 'host_yonetimi'
}
return render(request, 'ssh_manager/host_yonetimi.html', context)
def projeler(request):
"""Projeler sayfası"""
projects = Project.objects.all()
context = {
'projects': projects,
'page_title': 'Projeler',
'active_menu': 'projeler'
}
return render(request, 'ssh_manager/projeler.html', context)
def yedeklemeler(request):
"""Yedeklemeler sayfası"""
# Yedekleme kayıtlarını al
backups = Backup.objects.all().select_related('project', 'project__customer', 'project__ssh_credential').order_by('-start_time')
# Filtreler
status_filter = request.GET.get('status')
project_filter = request.GET.get('project')
if status_filter:
backups = backups.filter(status=status_filter)
if project_filter:
backups = backups.filter(project_id=project_filter)
# İstatistikler
total_backups = backups.count()
completed_backups = backups.filter(status='completed').count()
failed_backups = backups.filter(status='failed').count()
running_backups = backups.filter(status='running').count()
# Son 7 günün yedekleme sayısı
from datetime import datetime, timedelta
last_week = datetime.now() - timedelta(days=7)
recent_backups_count = backups.filter(start_time__gte=last_week).count()
# Projeler listesi (filtre için)
projects = Project.objects.all().order_by('name')
context = {
'backups': backups,
'projects': projects,
'backup_stats': {
'total': total_backups,
'completed': completed_backups,
'failed': failed_backups,
'running': running_backups,
},
'total_backups': total_backups,
'completed_backups': completed_backups,
'failed_backups': failed_backups,
'running_backups': running_backups,
'recent_backups_count': recent_backups_count,
'status_filter': status_filter,
'project_filter': project_filter,
'page_title': 'Yedeklemeler',
'active_menu': 'yedeklemeler'
}
return render(request, 'ssh_manager/yedeklemeler.html', context)
def ayarlar(request):
"""Ayarlar sayfası"""
from .system_settings import SystemSettings
# Ayarları al veya oluştur
settings, created = SystemSettings.objects.get_or_create(pk=1)
if request.method == 'POST':
# Yedekleme ayarlarını güncelle
try:
# Genel yedekleme ayarları
settings.backup_enabled = request.POST.get('backup_enabled') == 'on'
settings.backup_frequency = request.POST.get('backup_frequency', 'weekly')
settings.backup_hour = int(request.POST.get('backup_hour', 3))
settings.backup_minute = int(request.POST.get('backup_minute', 0))
# Seçilen sıklığa göre ek ayarları güncelle
if settings.backup_frequency == 'weekly':
settings.backup_day_of_week = int(request.POST.get('backup_day_of_week', 0))
elif settings.backup_frequency == 'monthly':
settings.backup_day_of_month = int(request.POST.get('backup_day_of_month', 1))
# Yedekleme format ayarı - sadece tar.gz destekleniyor
settings.backup_format = 'tar.gz'
# E-posta bildirim ayarları
settings.email_notifications = request.POST.get('email_notifications') == 'on'
settings.notification_email = request.POST.get('notification_email')
# Vultr S3 depolama ayarları (her zaman aktif)
settings.use_s3_storage = True
settings.s3_access_key = request.POST.get('s3_access_key')
settings.s3_secret_key = request.POST.get('s3_secret_key')
settings.s3_bucket_name = request.POST.get('s3_bucket_name')
settings.s3_region = request.POST.get('s3_region')
settings.s3_endpoint = request.POST.get('s3_endpoint', 'ams1.vultrobjects.com')
settings.save()
# Crontab kurulumunu kontrol et
if settings.backup_enabled:
setup_crontab(settings)
messages.success(request, 'Yedekleme ayarları başarıyla güncellendi!')
return redirect('ayarlar')
except ValueError as ve:
messages.error(request, f'Doğrulama hatası: {str(ve)}')
except Exception as e:
messages.error(request, f'Hata oluştu: {str(e)}')
context = {
'page_title': 'Ayarlar',
'active_menu': 'ayarlar',
'settings': settings
}
return render(request, 'ssh_manager/ayarlar.html', context)
def setup_crontab(settings):
"""Linux crontab yapılandırmasını ayarla - Sadece S3 depolama için"""
from .ssh_client import SSHManager
from .models import SSHCredential
# Tüm SSH kimlik bilgilerini kontrol et
credentials = SSHCredential.objects.filter(is_default=True)
if not credentials.exists():
credentials = SSHCredential.objects.all()[:1]
if not credentials.exists():
return False
credential = credentials.first()
ssh_manager = credential.get_manager()
try:
if ssh_manager.check_connection():
# Geçici yedekleme dizini
temp_backup_dir = "/tmp/backups"
# Script detayları
creation_date = timezone.now().strftime('%Y-%m-%d %H:%M')
email_notifications = str(settings.email_notifications).lower()
notification_email = settings.notification_email or "root@localhost"
bucket_name = settings.s3_bucket_name
s3_access_key = settings.s3_access_key
s3_secret_key = settings.s3_secret_key
s3_region = settings.s3_region
s3_endpoint = settings.s3_endpoint
# Bash script içeriği
script_content = """#!/bin/bash
# Otomatik oluşturulan yedekleme betiği (Vultr S3 Özel - Yıl/Ay/Hafta organizasyonlu)
# Oluşturulma tarihi: {0}
# Geçici yedekleme dizini
TEMP_BACKUP_DIR="{1}"
mkdir -p $TEMP_BACKUP_DIR
# Log dosyası
LOG_FILE="$TEMP_BACKUP_DIR/backup_$(date +%Y%m%d).log"
echo "S3 Yedekleme işlemi başlatıldı - $(date)" > $LOG_FILE
# AWS CLI kurulum kontrolü
if ! command -v aws &> /dev/null; then
echo "AWS CLI bulunamadı, kuruluyor..." >> $LOG_FILE
pip3 install awscli --upgrade >> $LOG_FILE 2>&1 || apt-get update && apt-get -y install awscli >> $LOG_FILE 2>&1
fi
# S3 kimlik bilgileri
export AWS_ACCESS_KEY_ID="{2}"
export AWS_SECRET_ACCESS_KEY="{3}"
export AWS_DEFAULT_REGION="{4}"
export AWS_ENDPOINT_URL="https://{5}"
# Tüm projeler için yedekleme işlemi
for PROJECT_DIR in /var/www/*/; do
if [ -d "$PROJECT_DIR" ]; then
PROJECT_NAME=$(basename "$PROJECT_DIR")
echo "Proje $PROJECT_NAME yedekleniyor..." >> $LOG_FILE
# Tarih değişkenlerini oluştur
YEAR=$(date +%Y)
MONTH=$(date +%m)
WEEK=$(date +%V)
DATE_TIME=$(date +%Y%m%d_%H%M%S)
# Yedekleme dosyası oluştur
BACKUP_FILE="$TEMP_BACKUP_DIR/$PROJECT_NAME-$DATE_TIME.tar.gz"
tar -czf "$BACKUP_FILE" -C /var/www/ "$PROJECT_NAME" --exclude="*/venv/*" --exclude="*/yedek/*" --exclude="*/.idea/*" --exclude="*/.sock/*" --exclude="*/.venv/*" --exclude="*.zip" >> $LOG_FILE 2>&1
# Dosya boyutunu kontrol et
if [ -f "$BACKUP_FILE" ]; then
FILE_SIZE=$(stat -c%s "$BACKUP_FILE" 2>/dev/null || stat -f%z "$BACKUP_FILE" 2>/dev/null)
echo "Yedek dosya boyutu: $FILE_SIZE byte" >> $LOG_FILE
# Yıllık yedek
echo "Vultr S3'e yıllık yedek olarak yükleniyor..." >> $LOG_FILE
aws s3 cp "$BACKUP_FILE" "s3://{6}/$PROJECT_NAME/yearly/$YEAR/$PROJECT_NAME-$DATE_TIME.tar.gz" --endpoint-url="https://{5}" >> $LOG_FILE 2>&1
# Aylık yedek
echo "Vultr S3'e aylık yedek olarak yükleniyor..." >> $LOG_FILE
aws s3 cp "$BACKUP_FILE" "s3://{6}/$PROJECT_NAME/monthly/$YEAR-$MONTH/$PROJECT_NAME-$DATE_TIME.tar.gz" --endpoint-url="https://{5}" >> $LOG_FILE 2>&1
# Haftalık yedek
echo "Vultr S3'e haftalık yedek olarak yükleniyor..." >> $LOG_FILE
aws s3 cp "$BACKUP_FILE" "s3://{6}/$PROJECT_NAME/weekly/$YEAR-W$WEEK/$PROJECT_NAME-$DATE_TIME.tar.gz" --endpoint-url="https://{5}" >> $LOG_FILE 2>&1
if [ $? -eq 0 ]; then
echo "Vultr S3'e yükleme başarılı" >> $LOG_FILE
# Başarılı yükleme sonrası yerel dosyayı sil
rm -f "$BACKUP_FILE"
else
echo "Vultr S3'e yükleme başarısız!" >> $LOG_FILE
fi
else
echo "Yedekleme dosyası oluşturulamadı: $BACKUP_FILE" >> $LOG_FILE
fi
fi
done
# Eski geçici dosyaları temizle (3 günden eski)
find $TEMP_BACKUP_DIR -type f -mtime +3 -delete
# E-posta bildirimi gönder
if [ -f /usr/bin/mail ] && [ "{7}" = "true" ]; then
echo "Yedekleme özeti gönderiliyor..." >> $LOG_FILE
cat $LOG_FILE | mail -s "Vultr S3 Yedekleme Özeti - $(date +%Y-%m-%d)" {8}
fi
echo "Yedekleme işlemi tamamlandı - $(date)" >> $LOG_FILE
""".format(
creation_date,
temp_backup_dir,
s3_access_key,
s3_secret_key,
s3_region,
s3_endpoint,
bucket_name,
email_notifications,
notification_email
)
# Betiği uzak sunucuya yükle
script_path = "/usr/local/bin/s3_backup.sh"
ssh_manager.execute_command(f"echo '{script_content}' > {script_path}")
ssh_manager.execute_command(f"chmod +x {script_path}")
# Crontab'a ekle
cron_expression = settings.backup_crontab_expression
cron_command = f"{cron_expression} root {script_path} > /dev/null 2>&1"
# Mevcut crontab'ı kontrol et ve güncelle
check_cron = "grep -l 's3_backup.sh' /etc/cron.d/s3_backup 2>/dev/null || echo 'notfound'"
stdout, stderr, status = ssh_manager.execute_command(check_cron)
if not status or 'notfound' in stdout:
# Crontab dosyasını oluştur
ssh_manager.execute_command(f"echo '{cron_command}' > /etc/cron.d/s3_backup")
ssh_manager.execute_command("chmod 644 /etc/cron.d/s3_backup")
else:
# Crontab dosyasını güncelle
ssh_manager.execute_command(f"sed -i 's|.* root /usr/local/bin/s3_backup.sh.*|{cron_command}|' /etc/cron.d/s3_backup")
# Eski backup betiklerini temizle
ssh_manager.execute_command("rm -f /usr/local/bin/auto_backup.sh /etc/cron.d/auto_backup")
return True
except Exception as e:
print(f"Crontab kurulumu hatası: {str(e)}")
return False
finally:
ssh_manager.close()
return False
# Müşteri Yönetimi Views
def musteriler(request):
"""Müşteriler sayfası"""
customers = Customer.objects.all().order_by('-created_at')
# Müşteri tipine göre filtrele
customer_type = request.GET.get('type')
if customer_type in ['individual', 'corporate']:
customers = customers.filter(customer_type=customer_type)
context = {
'customers': customers,
'page_title': 'Müşteriler',
'active_menu': 'musteriler',
'filter_type': customer_type
}
return render(request, 'ssh_manager/musteriler.html', context)
def create_customer(request):
"""Yeni müşteri oluştur"""
if request.method == 'POST':
try:
customer_type = request.POST.get('customer_type')
name = request.POST.get('name')
email = request.POST.get('email')
# Zorunlu alan kontrolü
if not all([customer_type, name, email]):
return JsonResponse({
'success': False,
'message': 'Gerekli alanlar eksik!'
})
# E-posta benzersizlik kontrolü
if Customer.objects.filter(email=email).exists():
return JsonResponse({
'success': False,
'message': 'Bu e-posta adresi zaten kullanılıyor!'
})
# Müşteri oluştur
customer = Customer(
customer_type=customer_type,
name=name,
email=email,
phone=request.POST.get('phone', ''),
address=request.POST.get('address', ''),
notes=request.POST.get('notes', '')
)
# Müşteri tipine göre alanları doldur
if customer_type == 'individual':
customer.surname = request.POST.get('surname', '')
customer.tc_number = request.POST.get('tc_number', '')
birth_date = request.POST.get('birth_date')
if birth_date:
customer.birth_date = birth_date
elif customer_type == 'corporate':
customer.company_name = request.POST.get('company_name', '')
customer.authorized_person = request.POST.get('authorized_person', '')
customer.tax_number = request.POST.get('tax_number', '')
customer.tax_office = request.POST.get('tax_office', '')
# Validasyon
customer.full_clean()
customer.save()
return JsonResponse({
'success': True,
'message': 'Müşteri başarıyla oluşturuldu!'
})
except ValidationError as e:
return JsonResponse({
'success': False,
'message': str(e)
})
except Exception as e:
logger.exception("Müşteri oluşturma hatası")
return JsonResponse({
'success': False,
'message': f'Müşteri oluşturulamadı: {str(e)}'
})
return JsonResponse({'success': False, 'message': 'Geçersiz istek!'})
def get_customer_details(request, customer_id):
"""Müşteri detaylarını getir"""
try:
customer = get_object_or_404(Customer, id=customer_id)
customer_data = {
'id': customer.id,
'customer_type': customer.customer_type,
'name': customer.name,
'email': customer.email,
'phone': customer.phone,
'address': customer.address,
'notes': customer.notes,
'surname': customer.surname,
'tc_number': customer.tc_number,
'birth_date': customer.birth_date.strftime('%Y-%m-%d') if customer.birth_date else '',
'company_name': customer.company_name,
'authorized_person': customer.authorized_person,
'tax_number': customer.tax_number,
'tax_office': customer.tax_office,
}
return JsonResponse({
'success': True,
'customer': customer_data
})
except Exception as e:
logger.exception("Müşteri detay alma hatası")
return JsonResponse({
'success': False,
'message': f'Müşteri bilgisi alınamadı: {str(e)}'
})
def update_customer(request, customer_id):
"""Müşteri güncelle"""
if request.method == 'POST':
try:
customer = get_object_or_404(Customer, id=customer_id)
customer_type = request.POST.get('customer_type')
name = request.POST.get('name')
email = request.POST.get('email')
# Zorunlu alan kontrolü
if not all([customer_type, name, email]):
return JsonResponse({
'success': False,
'message': 'Gerekli alanlar eksik!'
})
# E-posta benzersizlik kontrolü (kendisi hariç)
if Customer.objects.filter(email=email).exclude(id=customer_id).exists():
return JsonResponse({
'success': False,
'message': 'Bu e-posta adresi zaten kullanılıyor!'
})
# Müşteriyi güncelle
customer.customer_type = customer_type
customer.name = name
customer.email = email
customer.phone = request.POST.get('phone', '')
customer.address = request.POST.get('address', '')
customer.notes = request.POST.get('notes', '')
# Müşteri tipine göre alanları güncelle
if customer_type == 'individual':
customer.surname = request.POST.get('surname', '')
customer.tc_number = request.POST.get('tc_number', '')
birth_date = request.POST.get('birth_date')
customer.birth_date = birth_date if birth_date else None
# Kurumsal alanları temizle
customer.company_name = ''
customer.authorized_person = ''
customer.tax_number = ''
customer.tax_office = ''
elif customer_type == 'corporate':
customer.company_name = request.POST.get('company_name', '')
customer.authorized_person = request.POST.get('authorized_person', '')
customer.tax_number = request.POST.get('tax_number', '')
customer.tax_office = request.POST.get('tax_office', '')
# Bireysel alanları temizle
customer.surname = ''
customer.tc_number = ''
customer.birth_date = None
# Validasyon
customer.full_clean()
customer.save()
return JsonResponse({
'success': True,
'message': 'Müşteri başarıyla güncellendi!'
})
except ValidationError as e:
return JsonResponse({
'success': False,
'message': str(e)
})
except Exception as e:
logger.exception("Müşteri güncelleme hatası")
return JsonResponse({
'success': False,
'message': f'Müşteri güncellenemedi: {str(e)}'
})
return JsonResponse({'success': False, 'message': 'Geçersiz istek!'})
def edit_customer(request, customer_id):
"""Müşteri düzenleme sayfası (gerekirse)"""
customer = get_object_or_404(Customer, id=customer_id)
# Bu view'ı şu an kullanmıyoruz, AJAX ile hallediyoruz
return redirect('musteriler')
def delete_customer(request, customer_id):
"""Müşteri sil"""
if request.method == 'POST':
try:
customer = get_object_or_404(Customer, id=customer_id)
# Müşteriye ait proje kontrolü
project_count = customer.project_set.count()
if project_count > 0:
return JsonResponse({
'success': False,
'message': f'Bu müşteriye ait {project_count} proje bulunuyor. Önce projeleri silin veya başka müşteriye atayın.'
})
customer_name = str(customer)
customer.delete()
return JsonResponse({
'success': True,
'message': f'{customer_name} başarıyla silindi!'
})
except Exception as e:
logger.exception("Müşteri silme hatası")
return JsonResponse({
'success': False,
'message': f'Müşteri silinemedi: {str(e)}'
})
return JsonResponse({'success': False, 'message': 'Geçersiz istek!'})
@csrf_exempt
def test_host_connection(request, host_id):
"""Host bağlantı testi"""
if request.method == 'POST':
try:
host = SSHCredential.objects.get(id=host_id)
client = SSHManager(host)
# Bağlantı testi ve disk kullanımı güncelleme
if client.check_connection():
# Disk kullanımı al
disk_info = client.get_disk_usage()
if disk_info and isinstance(disk_info, dict):
host.disk_usage = disk_info.get('usage_percent')
host.connection_status = 'connected'
host.last_checked = timezone.now()
host.save()
client.close()
disk_msg = f" Disk kullanımı: {host.disk_usage}%" if host.disk_usage else ""
return JsonResponse({
'success': True,
'message': f'{host.name} - Bağlantı başarılı!{disk_msg}'
})
else:
host.connection_status = 'failed'
host.last_checked = timezone.now()
host.save()
return JsonResponse({
'success': False,
'message': f'{host.name} - Bağlantı başarısız!'
})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def refresh_all_hosts(request):
"""Tüm hostları yenile"""
if request.method == 'POST':
try:
hosts = SSHCredential.objects.all()
success_count = 0
total_count = hosts.count()
for host in hosts:
try:
client = SSHManager(host)
if client.check_connection():
# Disk kullanımı al
disk_info = client.get_disk_usage()
if disk_info and isinstance(disk_info, dict):
host.disk_usage = disk_info.get('usage_percent')
host.connection_status = 'connected'
success_count += 1
else:
host.connection_status = 'failed'
host.last_checked = timezone.now()
host.save()
client.close()
except Exception as e:
host.connection_status = 'failed'
host.last_checked = timezone.now()
host.save()
return JsonResponse({
'success': True,
'message': f'{total_count} host kontrol edildi. {success_count} host başarılı.'
})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def create_host(request):
"""Yeni host oluştur"""
if request.method == 'POST':
try:
name = request.POST.get('name')
hostname = request.POST.get('hostname')
port = request.POST.get('port', 22)
username = request.POST.get('username')
password = request.POST.get('password')
base_path = request.POST.get('base_path', '/var/www')
is_default = request.POST.get('is_default') == 'on'
if not all([name, hostname, username]):
return JsonResponse({'success': False, 'message': 'Zorunlu alanları doldurun'})
# Eğer bu varsayılan olarak ayarlanıyorsa, diğerlerini güncelle
if is_default:
SSHCredential.objects.filter(is_default=True).update(is_default=False)
host = SSHCredential.objects.create(
name=name,
hostname=hostname,
port=port,
username=username,
password=password,
base_path=base_path,
is_default=is_default
)
return JsonResponse({
'success': True,
'message': f'Host "{name}" başarıyla oluşturuldu'
})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def update_host(request, host_id):
"""Host güncelle"""
if request.method == 'POST':
try:
host = SSHCredential.objects.get(id=host_id)
host.name = request.POST.get('name', host.name)
host.hostname = request.POST.get('hostname', host.hostname)
host.port = request.POST.get('port', host.port)
host.username = request.POST.get('username', host.username)
password = request.POST.get('password')
if password: # Yalnızca yeni şifre girilmişse güncelle
host.password = password
host.base_path = request.POST.get('base_path', host.base_path)
is_default = request.POST.get('is_default') == 'on'
if is_default and not host.is_default:
# Diğer varsayılanları kaldır
SSHCredential.objects.filter(is_default=True).update(is_default=False)
host.is_default = is_default
host.save()
return JsonResponse({
'success': True,
'message': f'Host "{host.name}" başarıyla güncellendi'
})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
def get_host_details(request, host_id):
"""Host detaylarını getir"""
try:
host = SSHCredential.objects.get(id=host_id)
return JsonResponse({
'success': True,
'host': {
'id': host.id,
'name': host.name,
'hostname': host.hostname,
'port': host.port,
'username': host.username,
'base_path': host.base_path,
'is_default': host.is_default
}
})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
@csrf_exempt
def delete_host(request, host_id):
"""Host sil"""
if request.method == 'DELETE':
try:
host = SSHCredential.objects.get(id=host_id)
# Varsayılan host silinirse uyarı ver
if host.is_default:
return JsonResponse({
'success': False,
'message': 'Varsayılan host silinemez. Önce başka bir host\'u varsayılan yapın.'
})
host_name = host.name
host.delete()
return JsonResponse({
'success': True,
'message': f'Host "{host_name}" başarıyla silindi'
})
except SSHCredential.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Host bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def test_host_connection_form(request):
"""Form verisiyle bağlantı testi"""
if request.method == 'POST':
try:
hostname = request.POST.get('hostname')
port = request.POST.get('port', 22)
username = request.POST.get('username')
password = request.POST.get('password')
if not all([hostname, username]):
return JsonResponse({'success': False, 'message': 'Hostname ve kullanıcı adı gerekli'})
# Geçici SSH credential oluştur
temp_host = SSHCredential(
hostname=hostname,
port=port,
username=username,
password=password
)
client = SSHManager(temp_host)
if client.check_connection():
client.close()
return JsonResponse({
'success': True,
'message': 'Bağlantı testi başarılı!'
})
else:
return JsonResponse({
'success': False,
'message': 'Bağlantı testi başarısız!'
})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def start_backup(request):
"""Tek proje yedekleme başlat"""
if request.method == 'POST':
try:
project_id = request.POST.get('project_id')
backup_type = request.POST.get('backup_type', 'full')
compress = request.POST.get('compress') == 'on'
note = request.POST.get('note', '')
if not project_id:
return JsonResponse({'success': False, 'message': 'Proje ID gerekli'})
project = Project.objects.get(id=project_id)
# Yedekleme işlemini başlat (arka planda)
from threading import Thread
def backup_project():
try:
ssh_manager = SSHManager(project.ssh_credential)
# Log kaydı oluştur
log = SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='backup',
command=f'Backup {project.name} ({backup_type})',
status='running'
)
if ssh_manager.check_connection():
# Yedekleme komutlarını çalıştır
backup_commands = []
if backup_type in ['full', 'files']:
# Dosya yedekleme
if compress:
backup_commands.append(f'cd {project.ssh_credential.base_path} && tar -czf {project.folder_name}_backup_{log.created_at.strftime("%Y%m%d_%H%M%S")}.tar.gz {project.folder_name}/')
else:
backup_commands.append(f'cd {project.ssh_credential.base_path} && cp -r {project.folder_name} {project.folder_name}_backup_{log.created_at.strftime("%Y%m%d_%H%M%S")}')
if backup_type in ['full', 'database']:
# Veritabanı yedekleme (örnek MySQL)
backup_commands.append(f'mysqldump -u username -p password database_name > {project.folder_name}_db_backup_{log.created_at.strftime("%Y%m%d_%H%M%S")}.sql')
outputs = []
for cmd in backup_commands:
output = ssh_manager.execute_command(cmd)
outputs.append(f"Command: {cmd}\nOutput: {output}")
log.output = '\n\n'.join(outputs)
log.status = 'success'
# Proje son yedekleme tarihini güncelle
project.last_backup = timezone.now()
project.save()
else:
log.output = 'SSH bağlantı hatası'
log.status = 'error'
log.save()
ssh_manager.close()
except Exception as e:
log.output = f'Yedekleme hatası: {str(e)}'
log.status = 'error'
log.save()
# Arka planda çalıştır
backup_thread = Thread(target=backup_project)
backup_thread.start();
return JsonResponse({
'success': True,
'message': f'{project.name} projesi için yedekleme başlatıldı'
})
except Project.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Proje bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def backup_all_projects(request):
"""Tüm projeleri yedekle"""
if request.method == 'POST':
try:
projects = Project.objects.filter(ssh_credential__isnull=False)
if not projects.exists():
return JsonResponse({'success': False, 'message': 'Yedeklenecek proje bulunamadı'})
# Her proje için yedekleme başlat
from threading import Thread
def backup_all():
for project in projects:
try:
ssh_manager = SSHManager(project.ssh_credential)
log = SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='backup',
command=f'Auto backup {project.name}',
status='running'
)
if ssh_manager.check_connection():
# Basit dosya yedekleme
cmd = f'cd {project.ssh_credential.base_path} && tar -czf {project.folder_name}_auto_backup_{log.created_at.strftime("%Y%m%d_%H%M%S")}.tar.gz {project.folder_name}/'
output = ssh_manager.execute_command(cmd)
log.output = f"Command: {cmd}\nOutput: {output}"
log.status = 'success'
project.last_backup = timezone.now()
project.save()
else:
log.output = 'SSH bağlantı hatası'
log.status = 'error'
log.save()
ssh_manager.close()
except Exception as e:
log.output = f'Yedekleme hatası: {str(e)}'
log.status = 'error'
log.save()
backup_thread = Thread(target=backup_all)
backup_thread.start()
return JsonResponse({
'success': True,
'message': f'{projects.count()} proje için toplu yedekleme başlatıldı'
})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@csrf_exempt
def retry_backup(request):
"""Yedeklemeyi tekrar dene"""
if request.method == 'POST':
try:
import json
data = json.loads(request.body)
project_id = data.get('project_id')
if not project_id:
return JsonResponse({'success': False, 'message': 'Proje ID gerekli'})
project = Project.objects.get(id=project_id)
# start_backup fonksiyonunu çağır
from django.test import RequestFactory
factory = RequestFactory()
retry_request = factory.post('/start-backup/', {
'project_id': project_id,
'backup_type': 'full',
'compress': 'on'
})
retry_request.META['HTTP_X_CSRFTOKEN'] = request.META.get('HTTP_X_CSRFTOKEN')
return start_backup(retry_request)
except Project.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Proje bulunamadı'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Hata: {str(e)}'})
return JsonResponse({'success': False, 'message': 'Geçersiz istek'})
@require_http_methods(["GET"])
def backup_details(request, backup_id):
"""Backup detaylarını getir"""
try:
backup = get_object_or_404(Backup, id=backup_id)
data = {
'success': True,
'backup': {
'id': backup.id,
'project_name': backup.project.name,
'project_folder': backup.project.folder_name,
'host_name': backup.project.ssh_credential.hostname,
'backup_type': backup.get_backup_type_display(),
'status': backup.get_status_display(),
'start_time': backup.start_time.strftime('%d.%m.%Y %H:%M:%S'),
'end_time': backup.end_time.strftime('%d.%m.%Y %H:%M:%S') if backup.end_time else None,
'duration': backup.duration,
'file_path': backup.file_path,
'file_size': backup.file_size,
'error_message': backup.error_message,
'notes': backup.notes,
}
}
return JsonResponse(data)
except Exception as e:
return JsonResponse({'success': False, 'message': 'Backup detayları alınırken hata oluştu.'})
@require_http_methods(["POST"])
def cancel_backup(request, backup_id):
"""Devam eden backup'ı iptal et"""
try:
backup = get_object_or_404(Backup, id=backup_id)
if backup.status != 'running':
return JsonResponse({
'success': False,
'message': 'Sadece devam eden yedeklemeler iptal edilebilir'
})
backup.status = 'cancelled'
backup.end_time = timezone.now()
backup.error_message = 'Kullanıcı tarafından iptal edildi'
backup.save()
return JsonResponse({
'success': True,
'message': 'Yedekleme başarıyla iptal edildi'
})
except Exception as e:
return JsonResponse({
'success': False,
'message': 'Yedekleme iptal edilirken hata oluştu'
})
@require_http_methods(["POST"])
def delete_backup_record(request, backup_id):
"""Backup kaydını sil"""
try:
backup = get_object_or_404(Backup, id=backup_id)
# Devam eden backup silinemez
if backup.status == 'running':
return JsonResponse({
'success': False,
'message': 'Devam eden yedekleme kaydı silinemez. Önce iptal edin.'
})
backup.delete()
return JsonResponse({
'success': True,
'message': 'Yedekleme kaydı başarıyla silindi'
})
except Exception as e:
return JsonResponse({
'success': False,
'message': 'Kayıt silinirken hata oluştu'
})
@login_required
@require_http_methods(["POST"])
def renew_host(request, project_id):
"""Projenin host yenileme tarihini domain bitiş tarihine veya 1 yıl ileriye al"""
try:
project = get_object_or_404(Project, id=project_id)
from datetime import date, datetime, timedelta
import calendar
import json # JSON import'u ekle
# Request body'den expiration_date var mı kontrol et
if request.method == 'POST' and request.body:
try:
data = json.loads(request.body)
expiration_date_str = data.get('expiration_date')
if expiration_date_str:
# ISO formatında tarih geldiğini varsayalım (YYYY-MM-DD)
try:
next_year = datetime.fromisoformat(expiration_date_str).date()
renewal_source = f"Domain expiration tarihi: {expiration_date_str}"
except ValueError:
# Tarih parse edilemezse 1 yıl sonrasını hesapla
logger.warning(f"Geçersiz tarih formatı: {expiration_date_str}")
today = date.today()
try:
next_year = today.replace(year=today.year + 1)
except ValueError:
next_year = today.replace(year=today.year + 1, day=28)
renewal_source = "Manuel yenileme (geçersiz tarih formatı nedeniyle)"
else:
# Tarih yoksa 1 yıl sonrasını hesapla
renewal_source = "Manuel yenileme (1 yıl)"
today = date.today()
try:
next_year = today.replace(year=today.year + 1)
except ValueError:
# 29 Şubat durumu için (artık yıldan normal yıla geçiş)
next_year = today.replace(year=today.year + 1, day=28)
except json.JSONDecodeError as json_error:
# JSON parse edilemezse 1 yıl sonrasını hesapla
logger.warning(f"JSON parse hatası: {json_error}")
renewal_source = "Manuel yenileme (JSON parse hatası)"
today = date.today()
try:
next_year = today.replace(year=today.year + 1)
except ValueError:
# 29 Şubat durumu için (artık yıldan normal yıla geçiş)
next_year = today.replace(year=today.year + 1, day=28)
else:
# POST değilse veya body yoksa 1 yıl sonrasını hesapla
renewal_source = "Manuel yenileme (1 yıl)"
today = date.today()
try:
next_year = today.replace(year=today.year + 1)
except ValueError:
# 29 Şubat durumu için (artık yıldan normal yıla geçiş)
next_year = today.replace(year=today.year + 1, day=28)
# Eski tarihi logla
old_date = project.host_renewal_date
print(f"=== HOST RENEWAL UPDATE DEBUG ===")
print(f"Project ID: {project_id}")
print(f"Project Name: {project.name}")
print(f"Old renewal date: {old_date}")
print(f"New renewal date: {next_year}")
print(f"Renewal source: {renewal_source}")
# Yeni tarihi ayarla
project.host_renewal_date = next_year
project.save()
# Kaydedildi mi kontrol et
project.refresh_from_db()
print(f"Database'den tekrar okunan tarih: {project.host_renewal_date}")
# Log kaydı oluştur
log_message = f"Host yenileme tarihi güncellendi. Eski tarih: {old_date or 'Yok'}, Yeni tarih: {next_year}, Kaynak: {renewal_source}"
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command="Host Yenileme",
output=log_message,
status=True
)
logger.info(f"Proje {project.name} (ID: {project_id}) host yenileme tarihi güncellendi: {next_year}")
return JsonResponse({
'success': True,
'message': f'Host yenileme tarihi {next_year.strftime("%d.%m.%Y")} olarak güncellendi',
'old_date': old_date.strftime("%d.%m.%Y") if old_date else None,
'new_date': next_year.strftime("%d.%m.%Y"),
'project_id': project_id,
'project_name': project.name,
'renewal_source': renewal_source,
'debug': {
'old_date_raw': str(old_date),
'new_date_raw': str(next_year),
'saved_successfully': True
}
})
except Exception as e:
logger.exception(f"Host yenileme hatası (Proje ID: {project_id}): {str(e)}")
return JsonResponse({
'success': False,
'message': f'Host yenileme sırasında hata oluştu: {str(e)}',
'debug': f'Error type: {type(e).__name__}'
}, status=500)
@login_required
def update_hosts_status(request):
"""Tüm hostların bağlantı durumunu ve disk kullanım bilgisini güncelle - HTTP view"""
if request.method == 'POST':
try:
# Mevcut utility fonksiyonu çağır
update_all_hosts_status()
messages.success(request, "Tüm hostların durumu başarıyla güncellendi.")
return JsonResponse({
'success': True,
'message': 'Tüm hostların durumu başarıyla güncellendi.'
})
except Exception as e:
logger.exception("Host durumu güncelleme hatası")
messages.error(request, f"Host durumu güncellenirken bir hata oluştu: {str(e)}")
return JsonResponse({
'success': False,
'message': f'Host durumu güncellenirken bir hata oluştu: {str(e)}'
}, status=500)
else:
return JsonResponse({
'success': False,
'message': 'Bu işlem için POST metodu gerekli'
}, status=400)
@require_http_methods(["GET"])
def get_project_meta_key(request, project_id):
"""Proje için meta verification key döndür"""
try:
project = get_object_or_404(Project, id=project_id)
# Meta key yoksa oluştur
if not project.meta_key:
project.generate_meta_key()
project.save()
# Meta tag'ı al
primary_meta, all_metas, comment_tag = project.get_meta_tag()
return JsonResponse({
'success': True,
'meta_key': primary_meta,
'all_formats': all_metas,
'comment_format': comment_tag,
'project_name': project.name,
'project_url': project.url
})
except Exception as e:
logger.exception(f"Meta key alma hatası (Proje ID: {project_id}): {str(e)}")
return JsonResponse({
'success': False,
'message': f'Meta key alınırken hata oluştu: {str(e)}'
}, status=500)