Files
hostpanel/ssh_manager/views.py
ilkeral 342f1314c7 yeni
2025-07-21 13:49:36 +03:00

2495 lines
92 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.views.decorators.http import require_http_methods
from django.db import models
from django.db.models import Q
from .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ı
if file_extension == '.zip':
unzip_cmd = f'cd {project.get_full_path()} && unzip -o "{zip_file.name}" && rm "{zip_file.name}"'
stdout, stderr, status = ssh_manager.execute_command(unzip_cmd)
if not status:
return JsonResponse({
'success': False,
'message': f'Zip dosyasıılamadı: {stderr}'
})
# Log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=f'Dosya başarıyla yüklendi: {zip_file.name}',
status=True
)
return JsonResponse({
'success': True,
'message': 'Dosya başarıyla yüklendi'
})
finally:
# Geçici dosyayı sil
if os.path.exists(file_path):
os.remove(file_path)
finally:
ssh_manager.close()
except Exception as e:
logger.exception("Dosya yükleme hatası")
return JsonResponse({
'success': False,
'message': f'Beklenmeyen bir hata oluştu: {str(e)}'
})
@require_http_methods(["POST"])
@csrf_exempt
def delete_project(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Önce proje klasörünün varlığını kontrol et
check_cmd = f'test -d "{project.get_full_path()}" && echo "exists" || echo "not exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
if stdout.strip() != "exists":
project.delete()
return JsonResponse({'success': True, 'message': 'Proje veritabanından silindi (klasör zaten silinmiş)'})
# Klasör varsa silme işlemini başlat
delete_cmd = f'rm -rf "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(delete_cmd)
if status:
project.delete()
return JsonResponse({'success': True, 'message': 'Proje başarıyla silindi'})
else:
return JsonResponse({'success': False, 'message': f'Proje silinirken hata oluştu: {stderr}'})
except Exception as e:
return JsonResponse({'success': False, 'message': f'Silme işlemi sırasında hata: {str(e)}'})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({'success': False, 'message': 'Proje bulunamadı'})
@require_http_methods(["POST"])
def setup_venv(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
logger.info(f"Setting up virtual environment for project: {project.name}")
# Virtual environment kurulumu
cmd = f'''
cd {project.get_full_path()} && \
python3 -m venv venv && \
sudo chown -R www-data:www-data venv && \
sudo chmod -R 755 venv
'''
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command="Virtual Environment Kurulumu",
output=f"Başarılı: {stdout}",
status=True
)
return JsonResponse({
'status': 'success',
'message': 'Virtual environment başarıyla oluşturuldu'
})
else:
error_msg = f'Virtual environment oluşturulamadı: {stderr}'
logger.error(error_msg)
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='command',
command="Virtual Environment Kurulumu",
output=f"Hata: {stderr}",
status=False
)
return JsonResponse({
'status': 'error',
'message': error_msg
}, status=500)
except Exception as e:
logger.exception("Error in setup_venv")
return JsonResponse({
'status': 'error',
'message': str(e)
}, status=500)
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def download_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# req.txt dosyasını kontrol et ve içeriğini al
check_cmd = f'test -f "{project.get_full_path()}/req.txt" && cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
if status:
response = HttpResponse(stdout, content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename="{project.folder_name}_req.txt"'
return response
else:
return HttpResponse('req.txt dosyası bulunamadı.', status=404)
except Exception as e:
return HttpResponse(f'Hata: {str(e)}', status=500)
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def check_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Tam yolu logla
full_path = project.get_full_path()
logger.info(f"Proje bilgileri:")
logger.info(f"Proje adı: {project.name}")
logger.info(f"Klasör adı: {project.folder_name}")
logger.info(f"Tam yol: {full_path}")
# Önce dosyanın varlığını kontrol et
check_cmd = f'test -f "{full_path}/req.txt" && echo "exists"'
check_stdout, check_stderr, check_status = ssh_manager.execute_command(check_cmd)
logger.info(f"Dosya kontrol komutu: {check_cmd}")
logger.info(f"Kontrol çıktısı: {check_stdout}")
if check_status and check_stdout.strip() == "exists":
# Dosya varsa içeriğini oku
cat_cmd = f'cat "{full_path}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(cat_cmd)
logger.info(f"Okuma komutu: {cat_cmd}")
logger.info(f"Okuma çıktısı: {stdout}")
logger.info(f"Okuma hatası: {stderr}")
if status and stdout.strip():
return JsonResponse({
'success': True,
'content': stdout
})
else:
error_msg = 'req.txt dosyası boş' if status else f'req.txt dosyası okunamadı: {stderr}'
logger.error(error_msg)
return JsonResponse({
'success': False,
'message': error_msg
})
else:
error_msg = 'req.txt dosyası bulunamadı'
logger.error(error_msg)
return JsonResponse({
'success': False,
'message': error_msg
})
except Exception as e:
logger.exception("req.txt kontrol hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def download_req_file(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Dosya içeriğini doğrudan oku
command = f'cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(command)
if not status:
return JsonResponse({
'success': False,
'message': 'req.txt dosyası bulunamadı'
})
# Dosya içeriği varsa, indirme yanıtı oluştur
response = HttpResponse(stdout, content_type='text/plain')
response['Content-Disposition'] = f'attachment; filename="{project.folder_name}_req.txt"'
# Log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='download',
command='Requirements İndirme',
output=f'req.txt dosyası indirildi: {project.folder_name}',
status=True
)
return response
finally:
ssh_manager.close()
except Exception as e:
logger.exception("Requirements indirme hatası")
return JsonResponse({
'success': False,
'message': f'Dosya indirme hatası: {str(e)}'
})
def create_system_log(message, status=True, log_type='system', ssh_credential=None, command=None, output=None):
"""Sistem logu oluştur ve JSON olarak dön"""
log = SSHLog.objects.create(
ssh_credential=ssh_credential,
log_type=log_type,
command=command or 'Sistem',
output=output or message,
status=status
)
return {
'id': log.id,
'timestamp': log.created_at.strftime('%H:%M:%S'),
'message': message,
'command': command,
'output': output,
'status': status
}
@require_http_methods(["POST"])
def clear_logs(request):
try:
# Tüm logları sil
SSHLog.objects.all().delete()
# Log oluştur
SSHLog.objects.create(
ssh_credential=SSHCredential.objects.first(),
log_type='command',
command='Clear Logs',
output='Tüm log kayıtları temizlendi',
status=True
)
return JsonResponse({
'success': True,
'message': 'Loglar başarıyla temizlendi'
})
except Exception as e:
logger.exception("Log temizleme hatası")
return JsonResponse({
'success': False,
'message': f'Loglar temizlenirken hata oluştu: {str(e)}'
}, status=500)
@require_http_methods(["GET"])
def check_venv(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# venv klasörünün varlığını kontrol et
check_cmd = f'test -d "{project.get_full_path()}/venv" && echo "exists" || echo "not exists"'
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
exists = stdout.strip() == "exists"
log_data = create_system_log(
message=f'Virtual environment kontrolü: {"Mevcut" if exists else "Mevcut değil"}',
status=True,
ssh_credential=project.ssh_credential,
command='Venv Kontrolü',
output=f'Proje: {project.name}'
)
return JsonResponse({
'success': True,
'exists': exists,
'log': log_data
})
except Exception as e:
logger.exception("Venv kontrol hatası")
log_data = create_system_log(
message=f'Virtual environment kontrol hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Venv Kontrolü'
)
return JsonResponse({
'success': False,
'exists': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def install_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Venv'i aktive et ve pip install çalıştır
cmd = f'''
cd {project.get_full_path()} && \
source venv/bin/activate && \
if [ -f "req.txt" ]; then
pip install -r req.txt
else
echo "req.txt dosyası bulunamadı"
exit 1
fi
'''
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
log_data = create_system_log(
message='Paketler başarıyla kuruldu',
status=True,
ssh_credential=project.ssh_credential,
command='Pip Install',
output=stdout
)
else:
log_data = create_system_log(
message='Paket kurulumu başarısız oldu',
status=False,
ssh_credential=project.ssh_credential,
command='Pip Install',
output=stderr
)
return JsonResponse({
'success': status,
'log': log_data
})
except Exception as e:
logger.exception("Paket kurulum hatası")
log_data = create_system_log(
message=f'Paket kurulum hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Pip Install'
)
return JsonResponse({
'success': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["GET"])
def check_folder_empty(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Klasördeki dosya ve klasörleri listele
cmd = f'ls -A "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(cmd)
is_empty = not stdout.strip() # Boş string ise klasör boştur
if not is_empty:
files = stdout.strip().split('\n')
log_data = create_system_log(
message=f'Klasör içeriği kontrol edildi: {len(files)} öğe mevcut',
status=True,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü',
output=f'Mevcut dosyalar: {", ".join(files)}'
)
else:
log_data = create_system_log(
message='Klasör boş',
status=True,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü'
)
return JsonResponse({
'success': True,
'is_empty': is_empty,
'files': stdout.strip().split('\n') if not is_empty else [],
'log': log_data
})
except Exception as e:
logger.exception("Klasör kontrol hatası")
log_data = create_system_log(
message=f'Klasör kontrol hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Klasör Kontrolü'
)
return JsonResponse({
'success': False,
'log': log_data
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@login_required
def list_project_files(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = SSHManager(project.ssh_credential)
if not ssh_manager.check_connection():
return JsonResponse({
'success': False,
'message': 'SSH bağlantısı kurulamadı!'
})
# Proje klasöründeki dosyaları listele
cmd = f'ls -la "{project.get_full_path()}"'
stdout, stderr, status = ssh_manager.execute_command(cmd)
if not status:
return JsonResponse({
'success': False,
'message': f'Dosya listesi alınamadı: {stderr}'
})
# ls -la çıktısını parse et
files = []
for line in stdout.splitlines()[1:]: # İlk satırı atla (toplam)
if line.strip():
parts = line.split()
if len(parts) >= 9:
permissions = parts[0]
size = parts[4]
date = ' '.join(parts[5:8])
name = ' '.join(parts[8:])
files.append({
'name': name,
'permissions': permissions,
'size': size,
'date': date
})
return JsonResponse({
'success': True,
'files': files
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı!'
})
except Exception as e:
logger.exception("Dosya listeleme hatası")
return JsonResponse({
'success': False,
'message': f'Beklenmeyen bir hata oluştu: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@login_required
def upload_project_files(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = SSHManager(project.ssh_credential)
try:
success, ssh_message = ssh_manager.upload_project_zip(project, request.FILES['files'])
if success:
# Başarılı durumda log oluştur
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=ssh_message, # SSH'den dönen detaylı başarı mesajı
status=True
)
# Kullanıcıya genel başarı mesajı
return JsonResponse({
'success': True,
'message': 'Dosyalar başarıyla yüklendi'
})
else:
# Hata durumunda detaylı log oluştur
logger.error(ssh_message) # SSH hatasını direkt logla
SSHLog.objects.create(
ssh_credential=project.ssh_credential,
log_type='upload',
command='Dosya Yükleme',
output=ssh_message, # SSH'den dönen detaylı hata mesajı
status=False
)
# Kullanıcıya genel hata mesajı
return JsonResponse({
'success': False,
'message': 'Dosya yükleme işlemi başarısız oldu'
})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
})
except Exception as e:
# Beklenmeyen hataları detaylı şekilde logla
logger.exception('Beklenmeyen bir hata oluştu')
SSHLog.objects.create(
ssh_credential=project.ssh_credential if 'project' in locals() else None,
log_type='upload',
command='Dosya Yükleme',
output=str(e), # Ham hata mesajı
status=False
)
# Kullanıcıya genel hata mesajı
return JsonResponse({
'success': False,
'message': 'Beklenmeyen bir hata oluştu'
})
@require_http_methods(["POST"])
def get_latest_logs(request):
logs = SSHLog.objects.all().order_by('-created_at')[:50] # Son 50 log
log_data = [{
'created_at': log.created_at.strftime('%d.%m.%Y %H:%M:%S'),
'log_type_display': log.get_log_type_display(),
'command': log.command,
'output': log.output,
'status': log.status
} for log in logs]
return JsonResponse({'logs': log_data})
@require_http_methods(["POST"])
def restart_supervisor(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
try:
# Supervisor'ı yeniden başlat
cmd = f'sudo supervisorctl restart {project.folder_name}'
stdout, stderr, status = ssh_manager.execute_command(cmd)
if status:
log_data = create_system_log(
message='Supervisor başarıyla yeniden başlatıldı',
status=True,
ssh_credential=project.ssh_credential,
command='Supervisor Restart',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Uygulama başarıyla yeniden başlatıldı',
'log': log_data
})
else:
log_data = create_system_log(
message='Supervisor yeniden başlatılamadı',
status=False,
ssh_credential=project.ssh_credential,
command='Supervisor Restart',
output=stderr
)
return JsonResponse({
'success': False,
'message': 'Uygulama yeniden başlatılamadı',
'log': log_data
})
except Exception as e:
logger.exception("Supervisor restart hatası")
log_data = create_system_log(
message=f'Supervisor restart hatası: {str(e)}',
status=False,
ssh_credential=project.ssh_credential,
command='Supervisor Restart'
)
return JsonResponse({
'success': False,
'message': str(e),
'log': log_data
})
finally:
ssh_manager.close()
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
})
@require_http_methods(["POST"])
def update_requirements(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# JSON verilerini al
data = json.loads(request.body)
new_content = data.get('content', '')
# Yeni içeriği req.txt dosyasına yaz
write_cmd = f'echo "{new_content}" > "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(write_cmd)
if status:
log_data = create_system_log(
message='Requirements içeriği güncellendi',
status=True,
ssh_credential=project.ssh_credential,
command='Requirements Güncelleme',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Requirements içeriği başarıyla güncellendi',
'log': log_data
})
else:
log_data = create_system_log(
message='Requirements güncellenirken hata oluştu',
status=False,
ssh_credential=project.ssh_credential,
command='Requirements Güncelleme',
output=stderr
)
return JsonResponse({
'success': False,
'message': f'Requirements güncellenirken hata oluştu: {stderr}',
'log': log_data
})
except Exception as e:
logger.exception("Requirements güncelleme hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def delete_requirement_line(request, project_id):
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# JSON verilerini al
data = json.loads(request.body)
line_index = int(data.get('line_index', -1)) # int'e çevir
# Mevcut içeriği oku
read_cmd = f'cat "{project.get_full_path()}/req.txt"'
stdout, stderr, status = ssh_manager.execute_command(read_cmd)
if not status:
return JsonResponse({
'success': False,
'message': 'Requirements dosyası okunamadı'
})
# Satırları ayır ve belirtilen satırı sil
lines = [line for line in stdout.strip().split('\n') if line.strip()] # Boş satırları filtrele
if 0 <= line_index < len(lines):
deleted_line = lines.pop(line_index)
new_content = '\n'.join(lines)
# Yeni içeriği dosyaya yaz
write_cmd = f"echo '{new_content}' > '{project.get_full_path()}/req.txt'"
stdout, stderr, status = ssh_manager.execute_command(write_cmd)
if status:
log_data = create_system_log(
message=f'Requirements satırı silindi: {deleted_line}',
status=True,
ssh_credential=project.ssh_credential,
command='Requirements Satır Silme',
output=stdout
)
return JsonResponse({
'success': True,
'message': 'Satır başarıyla silindi',
'content': new_content,
'log': log_data
})
return JsonResponse({
'success': False,
'message': 'Satır silinemedi'
})
except Exception as e:
logger.exception("Requirements satır silme hatası")
return JsonResponse({
'success': False,
'message': f'Hata: {str(e)}'
})
finally:
if 'ssh_manager' in locals():
ssh_manager.close()
@require_http_methods(["POST"])
def refresh_project(request, project_id):
ssh_manager = None
try:
project = get_object_or_404(Project, id=project_id)
ssh_manager = project.ssh_credential.get_manager()
# Proje klasörünü kontrol et
project_path = project.get_full_path()
# Disk kullanımını hesapla (du komutu ile)
du_cmd = f"du -sh {project_path}"
stdout, stderr, status = ssh_manager.execute_command(du_cmd)
if status:
# du çıktısını parse et (örn: "156M /path/to/folder")
disk_usage = stdout.split()[0]
project.disk_usage = disk_usage
project.save()
# Requirements dosyasını kontrol et (req.txt)
stdout, stderr, status = ssh_manager.execute_command(f"ls {project_path}/req.txt")
has_requirements = status
# Requirements içeriğini al
if has_requirements:
stdout, stderr, status = ssh_manager.execute_command(f"cat {project_path}/req.txt")
req_content = stdout if status else ""
else:
req_content = ""
# Log oluştur
log_data = create_system_log(
message='Proje bilgileri güncellendi',
status=True,
ssh_credential=project.ssh_credential,
command='Proje Güncelleme',
output=f"Requirements durumu: {'Mevcut' if has_requirements else 'Mevcut değil'}"
)
return JsonResponse({
'success': True,
'project_info': {
'base_path': project.ssh_credential.base_path,
'folder_name': project.folder_name,
'disk_usage': project.disk_usage or '0B'
},
'has_requirements': has_requirements,
'requirements_content': req_content,
'message': 'Proje başarıyla güncellendi',
'log': log_data
})
except Project.DoesNotExist:
return JsonResponse({
'success': False,
'message': 'Proje bulunamadı'
}, status=404)
except Exception as e:
logger.exception("Proje güncelleme hatası")
log_data = create_system_log(
message=f'Proje güncellenirken hata oluştu: {str(e)}',
status=False,
ssh_credential=project.ssh_credential if 'project' in locals() else None,
command='Proje Güncelleme'
)
return JsonResponse({
'success': False,
'message': str(e),
'log': log_data
}, status=500)
finally:
if ssh_manager:
ssh_manager.close()
# @require_http_methods(["POST"])
# def backup_projects(request):
# logger.info("====== BACKUP İŞLEMİ BAŞLIYOR ======")
#
# try:
# ssh_credential = SSHCredential.objects.first()
# if not ssh_credential:
# raise ValueError("SSH bağlantısı bulunamadı")
#
# # Başlangıç logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup İşlemi',
# output='Yedekleme işlemi başlatıldı',
# status=True
# )
#
# # Google Drive bağlantı logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Google Drive Bağlantısı',
# output='Google Drive API bağlantısı kuruluyor...',
# status=True
# )
#
# credentials = service_account.Credentials.from_service_account_info(
# settings.GOOGLE_DRIVE_CREDENTIALS,
# scopes=['https://www.googleapis.com/auth/drive.file']
# )
# drive_service = build('drive', 'v3', credentials=credentials)
#
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Google Drive Bağlantısı',
# output='Google Drive API bağlantısı başarıyla kuruldu',
# status=True
# )
#
# ssh_manager = ssh_credential.get_manager()
#
# try:
# for project in Project.objects.all():
# # Proje yedekleme başlangıç logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Proje: {project.name}',
# output=f'{project.name} projesi yedekleme işlemi başladı',
# status=True
# )
#
# backup_name = f'{project.folder_name}_{datetime.now().strftime("%Y%m%d_%H%M%S")}.zip'
# project_path = project.get_full_path()
#
# # Zip işlemi
# zip_cmd = f'''
# cd {project_path}/.. && \
# zip -9 -r "{project.folder_name}.zip" "{project.folder_name}" && \
# mv "{project.folder_name}.zip" "/tmp/{backup_name}"
# '''
# logger.info(f"Zip komutu çalıştırılıyor: {zip_cmd}")
#
# stdout, stderr, status = ssh_manager.execute_command(zip_cmd)
#
# if not status:
# error_msg = f"{project.name} için zip oluşturma hatası:\nStdout: {stdout}\nStderr: {stderr}"
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Zip Hatası: {project.name}',
# output=error_msg,
# status=False
# )
# continue
#
# # Zip dosyası boyutunu ve başarı durumunu logla
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Zip: {project.name}',
# output=f'{project.name} projesi için zip dosyası oluşturuldu\n{stdout}',
# status=True
# )
#
# # Dosya tipini kontrol et
# check_cmd = f'file "/tmp/{backup_name}"'
# stdout, stderr, status = ssh_manager.execute_command(check_cmd)
# logger.info(f"Dosya tipi kontrolü: {stdout}")
#
# # Dosya boyutunu kontrol et
# size_cmd = f'ls -lh "/tmp/{backup_name}"'
# size_out, size_err, size_status = ssh_manager.execute_command(size_cmd)
# logger.info(f"Dosya boyutu: {size_out}")
#
# if not status or 'Zip archive data' not in stdout:
# error_msg = f"Oluşturulan dosya bir zip arşivi değil: {stdout}"
# logger.error(error_msg)
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command=f'Kontrol: {project.name}',
# output=error_msg,
# status=False
# )
# continue
#
# # Google Drive yükleme işlemi...
# # ... (mevcut Drive yükleme kodu devam eder)
#
# # Tamamlanma logu
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup İşlemi',
# output='Tüm projelerin yedekleme işlemi başarıyla tamamlandı',
# status=True
# )
#
# return JsonResponse({
# 'success': True,
# 'message': 'Yedekleme işlemi tamamlandı!'
# })
#
# finally:
# ssh_manager.close()
#
# except Exception as e:
# error_msg = f"Yedekleme sırasında hata oluştu: {str(e)}"
# if 'ssh_credential' in locals():
# SSHLog.objects.create(
# ssh_credential=ssh_credential,
# log_type='backup',
# command='Backup Hatası',
# output=error_msg,
# status=False
# )
# return JsonResponse({
# 'success': False,
# 'message': error_msg
# })
@require_http_methods(["POST"])
def backup_project(request, project_id):
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 <head> 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'})