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ı aç 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ı açı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)