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 .backup import job from .models import SSHCredential, Project, SSHLog, Customer 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__) @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): try: project = get_object_or_404(Project, id=project_id) folder_name = project.folder_name calisma_dizini = f"{project.ssh_credential.base_path}/{folder_name}" if not folder_name: return JsonResponse({ 'success': False, 'message': 'Klasör adı bulunamadı' }) try: # Önce klasörün varlığını kontrol et ssh_manager = project.ssh_credential.get_manager() check_cmd = f'test -d "{calisma_dizini}" && echo "exists"' stdout, stderr, status = ssh_manager.execute_command(check_cmd) if not status or stdout.strip() != "exists": return JsonResponse({ 'success': False, 'message': 'Yedeklenecek klasör bulunamadı' }) # Backup işlemini başlat result = job(folder_name, calisma_dizini, project_id) if not result.get('success'): raise Exception(result.get('message', 'Backup işlemi başarısız oldu')) # 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: error_msg = str(e) if 'NoSuchBucket' in error_msg: error_msg = 'Backup bucket\'ı bulunamadı. Sistem yöneticinize başvurun.' # 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 '', 'last_backup': project.last_backup.strftime('%d.%m.%Y %H:%M') if project.last_backup else None, 'disk_usage': project.disk_usage or '0B', } } 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', '') # 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 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: status, message = check_site_status(project) # Host bilgilerini güncelle (bağlantı durumu ve disk kullanımı) 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 # Disk kullanım bilgisini al (sadece online ise) if is_online: disk_usage_info = ssh_manager.get_disk_usage() if disk_usage_info: # Dictionary'yi string'e çevir (görüntüleme için) project.ssh_credential.disk_usage = f"{disk_usage_info['used']} / {disk_usage_info['total']} ({disk_usage_info['usage_percent']}%)" else: project.ssh_credential.disk_usage = None else: project.ssh_credential.disk_usage = None project.ssh_credential.save() except Exception as e: # Hata durumunda offline olarak işaretle project.ssh_credential.is_online = False project.ssh_credential.disk_usage = None project.ssh_credential.save() print(f"Host bilgi güncelleme hatası: {e}") finally: ssh_manager.close() # Log kaydını güncelle log_entry.output = message log_entry.status = status log_entry.save() return JsonResponse({ 'success': True, 'status': status, 'message': message, 'is_active': project.is_site_active, '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"Site kontrol hatası: {str(e)}" log_entry.status = False log_entry.save() raise e except Exception as e: return JsonResponse({ 'success': False, 'message': f'Site kontrol hatası: {str(e)}' }, status=500) @require_http_methods(["GET"]) def get_project_meta_key(request, project_id): """Projenin meta key'ini döndür""" try: project = get_object_or_404(Project, id=project_id) if not project.meta_key: project.generate_meta_key() project.save() return JsonResponse({ 'success': True, 'meta_key': project.meta_key, 'meta_tag': project.get_meta_tag(), 'instructions': 'Bu meta tag\'ı sitenizin bölümüne ekleyin' }) except Exception as e: return JsonResponse({ 'success': False, 'message': f'Meta key hatası: {str(e)}' }, status=500) @require_http_methods(["POST"]) def check_all_sites_view(request): """Tüm projelerin site durumunu kontrol et""" try: from .utils import check_all_sites results = check_all_sites() return JsonResponse({ 'success': True, 'results': [ { 'project_id': result['project'].id, 'project_name': result['project'].name, 'status': result['status'], 'message': result['message'] } for result in results ] }) except Exception as e: return JsonResponse({ 'success': False, 'message': f'Toplu kontrol hatası: {str(e)}' }, status=500) @csrf_exempt def update_hosts_status(request): """Tüm hostların durumunu güncelle""" print(f"update_hosts_status çağrıldı, method: {request.method}") if request.method == 'POST': try: print("update_all_hosts_status fonksiyonu çağrılıyor...") update_all_hosts_status() print("update_all_hosts_status başarıyla tamamlandı") return JsonResponse({ 'success': True, 'message': 'Tüm host bilgileri güncellendi' }) except Exception as e: print(f"update_hosts_status hatası: {e}") return JsonResponse({ 'success': False, 'message': f'Host güncelleme hatası: {str(e)}' }) print("Geçersiz istek (POST değil)") return JsonResponse({'success': False, 'message': 'Geçersiz istek'}) @csrf_exempt 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 loglarını al backup_logs = SSHLog.objects.filter(log_type='backup').select_related('ssh_credential').order_by('-created_at') # İstatistikler total_backups = backup_logs.count() successful_backups = backup_logs.filter(status='success').count() failed_backups = backup_logs.filter(status='error').count() context = { 'backup_logs': backup_logs, 'total_backups': total_backups, 'successful_backups': successful_backups, 'failed_backups': failed_backups, 'page_title': 'Yedeklemeler', 'active_menu': 'yedeklemeler' } return render(request, 'ssh_manager/yedeklemeler.html', context) def ayarlar(request): """Ayarlar sayfası""" context = { 'page_title': 'Ayarlar', 'active_menu': 'ayarlar' } return render(request, 'ssh_manager/ayarlar.html', context) # 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 siliniyorsa 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'})