198 lines
8.6 KiB
Python
198 lines
8.6 KiB
Python
from django.db import models
|
||
import logging
|
||
from .ssh_client import SSHManager
|
||
from django.core.validators import URLValidator
|
||
from django.core.exceptions import ValidationError
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
def validate_domain(value):
|
||
"""Domain formatını kontrol et"""
|
||
if ' ' in value: # Boşluk kontrolü
|
||
raise ValidationError('Domain adında boşluk olamaz')
|
||
if not any(char.isalpha() for char in value): # En az bir harf kontrolü
|
||
raise ValidationError('Domain adında en az bir harf olmalıdır')
|
||
if not all(c.isalnum() or c in '-.' for c in value): # Geçerli karakter kontrolü
|
||
raise ValidationError('Domain adında sadece harf, rakam, tire (-) ve nokta (.) olabilir')
|
||
|
||
class Customer(models.Model):
|
||
CUSTOMER_TYPES = (
|
||
('individual', 'Bireysel'),
|
||
('corporate', 'Kurumsal'),
|
||
)
|
||
|
||
customer_type = models.CharField(max_length=20, choices=CUSTOMER_TYPES, verbose_name='Müşteri Tipi')
|
||
|
||
# Ortak alanlar
|
||
name = models.CharField(max_length=200, verbose_name='Ad/Firma Adı')
|
||
email = models.EmailField(verbose_name='E-posta')
|
||
phone = models.CharField(max_length=20, blank=True, null=True, verbose_name='Telefon')
|
||
address = models.TextField(blank=True, null=True, verbose_name='Adres')
|
||
|
||
# Bireysel müşteri alanları
|
||
surname = models.CharField(max_length=100, blank=True, null=True, verbose_name='Soyad')
|
||
birth_date = models.DateField(blank=True, null=True, verbose_name='Doğum Tarihi')
|
||
tc_number = models.CharField(max_length=11, blank=True, null=True, verbose_name='TC Kimlik No')
|
||
|
||
# Kurumsal müşteri alanları
|
||
company_name = models.CharField(max_length=200, blank=True, null=True, verbose_name='Şirket Adı')
|
||
tax_number = models.CharField(max_length=20, blank=True, null=True, verbose_name='Vergi No')
|
||
tax_office = models.CharField(max_length=100, blank=True, null=True, verbose_name='Vergi Dairesi')
|
||
authorized_person = models.CharField(max_length=200, blank=True, null=True, verbose_name='Yetkili Kişi')
|
||
|
||
# Genel bilgiler
|
||
notes = models.TextField(blank=True, null=True, verbose_name='Notlar')
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='Oluşturma Tarihi')
|
||
updated_at = models.DateTimeField(auto_now=True, verbose_name='Güncelleme Tarihi')
|
||
is_active = models.BooleanField(default=True, verbose_name='Aktif')
|
||
|
||
def __str__(self):
|
||
if self.customer_type == 'corporate':
|
||
return f"{self.company_name or self.name} (Kurumsal)"
|
||
else:
|
||
return f"{self.name} {self.surname or ''} (Bireysel)".strip()
|
||
|
||
def get_display_name(self):
|
||
"""Görüntüleme için uygun isim döndür"""
|
||
if self.customer_type == 'corporate':
|
||
return self.company_name or self.name
|
||
else:
|
||
return f"{self.name} {self.surname or ''}".strip()
|
||
|
||
def clean(self):
|
||
"""Model validasyonu"""
|
||
if self.customer_type == 'individual':
|
||
if not self.surname:
|
||
raise ValidationError('Bireysel müşteriler için soyad zorunludur.')
|
||
elif self.customer_type == 'corporate':
|
||
if not self.company_name:
|
||
raise ValidationError('Kurumsal müşteriler için şirket adı zorunludur.')
|
||
|
||
class Meta:
|
||
verbose_name = "Müşteri"
|
||
verbose_name_plural = "Müşteriler"
|
||
ordering = ['-created_at']
|
||
|
||
class SSHCredential(models.Model):
|
||
name = models.CharField(max_length=100, verbose_name='Host Adı', default='Varsayılan Host')
|
||
hostname = models.CharField(max_length=255)
|
||
username = models.CharField(max_length=100)
|
||
password = models.CharField(max_length=100)
|
||
port = models.IntegerField(default=22)
|
||
base_path = models.CharField(max_length=500, help_text="Projelerin oluşturulacağı ana dizin") # Yeni alan
|
||
is_default = models.BooleanField(default=False, verbose_name='Varsayılan Host')
|
||
connection_status = models.CharField(max_length=20, default='unknown', choices=[
|
||
('connected', 'Bağlı'),
|
||
('failed', 'Başarısız'),
|
||
('unknown', 'Bilinmiyor')
|
||
])
|
||
is_online = models.BooleanField(default=False) # Bağlantı durumu
|
||
last_check = models.DateTimeField(auto_now=True) # Son kontrol zamanı
|
||
last_checked = models.DateTimeField(null=True, blank=True, verbose_name='Son Kontrol')
|
||
disk_usage = models.FloatField(null=True, blank=True, verbose_name='Disk Kullanımı (%)')
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
def get_manager(self):
|
||
"""SSHManager instance'ı döndür"""
|
||
return SSHManager(self)
|
||
|
||
def __str__(self):
|
||
return f"{self.username}@{self.hostname}"
|
||
|
||
class Project(models.Model):
|
||
name = models.CharField(max_length=100, verbose_name='Proje Adı')
|
||
folder_name = models.CharField(max_length=100, verbose_name='Klasör Adı')
|
||
ssh_credential = models.ForeignKey(SSHCredential, on_delete=models.CASCADE)
|
||
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, verbose_name='Müşteri', null=True, blank=True)
|
||
url = models.CharField(max_length=255, null=True, blank=True)
|
||
disk_usage = models.CharField(max_length=20, null=True, blank=True)
|
||
last_backup = models.DateTimeField(null=True, blank=True, verbose_name='Son Yedekleme')
|
||
meta_key = models.CharField(max_length=32, null=True, blank=True, verbose_name='Meta Key', help_text='Site aktiflik kontrolü için benzersiz anahtar')
|
||
is_site_active = models.BooleanField(default=False, verbose_name='Site Aktif')
|
||
last_site_check = models.DateTimeField(null=True, blank=True, verbose_name='Son Site Kontrolü')
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
updated_at = models.DateTimeField(auto_now=True)
|
||
|
||
def generate_meta_key(self):
|
||
"""Benzersiz meta key oluştur"""
|
||
import uuid
|
||
self.meta_key = uuid.uuid4().hex[:32]
|
||
return self.meta_key
|
||
|
||
def get_meta_tag(self):
|
||
"""HTML meta tag'ı döndür"""
|
||
if not self.meta_key:
|
||
self.generate_meta_key()
|
||
self.save()
|
||
return f'<meta name="site-verification" content="{self.meta_key}">'
|
||
|
||
def clean(self):
|
||
# URL formatını kontrol et
|
||
if self.url:
|
||
# URL'den http/https ve www. kısımlarını temizle
|
||
cleaned_url = self.url.lower()
|
||
for prefix in ['http://', 'https://', 'www.']:
|
||
if cleaned_url.startswith(prefix):
|
||
cleaned_url = cleaned_url[len(prefix):]
|
||
# Sondaki / işaretini kaldır
|
||
cleaned_url = cleaned_url.rstrip('/')
|
||
self.url = cleaned_url
|
||
|
||
def save(self, *args, **kwargs):
|
||
self.clean()
|
||
super().save(*args, **kwargs)
|
||
|
||
def get_full_path(self):
|
||
"""Projenin tam yolunu döndür"""
|
||
return f"{self.ssh_credential.base_path}/{self.folder_name}"
|
||
|
||
@property
|
||
def has_requirements(self):
|
||
"""Projenin req.txt dosyası var mı kontrol et"""
|
||
try:
|
||
ssh_manager = self.ssh_credential.get_manager()
|
||
check_cmd = f'test -f "{self.get_full_path()}/req.txt" && echo "exists"'
|
||
stdout, stderr, status = ssh_manager.execute_command(check_cmd)
|
||
|
||
# Debug için log ekle
|
||
logger.info(f"has_requirements check for project {self.id}")
|
||
logger.info(f"Command: {check_cmd}")
|
||
logger.info(f"Status: {status}, Stdout: {stdout}, Stderr: {stderr}")
|
||
|
||
return status and stdout.strip() == "exists"
|
||
except Exception as e:
|
||
logger.exception(f"Error checking requirements for project {self.id}")
|
||
return False
|
||
finally:
|
||
if 'ssh_manager' in locals():
|
||
ssh_manager.close()
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Proje"
|
||
verbose_name_plural = "Projeler"
|
||
ordering = ['-created_at']
|
||
|
||
class SSHLog(models.Model):
|
||
LOG_TYPES = (
|
||
('connection', 'Bağlantı Kontrolü'),
|
||
('command', 'Komut Çalıştırma'),
|
||
('folder', 'Klasör İşlemi'),
|
||
('file', 'Dosya İşlemi'),
|
||
('backup', 'Yedekleme'), # Yeni tip ekleyelim
|
||
)
|
||
|
||
ssh_credential = models.ForeignKey(SSHCredential, on_delete=models.CASCADE)
|
||
log_type = models.CharField(max_length=20, choices=LOG_TYPES)
|
||
command = models.TextField()
|
||
output = models.TextField()
|
||
status = models.BooleanField(default=True)
|
||
created_at = models.DateTimeField(auto_now_add=True)
|
||
|
||
def __str__(self):
|
||
return f"{self.ssh_credential.hostname} - {self.log_type} - {self.created_at}"
|
||
|
||
class Meta:
|
||
ordering = ['-created_at'] |