LOT 1 - Optimizare script build -Instalare mono comanda
This commit is contained in:
parent
5380c3fc63
commit
42ff22bf85
127 changed files with 16163 additions and 532 deletions
26
ai_platform/modules/domain_check/api/app/models/__init__.py
Normal file
26
ai_platform/modules/domain_check/api/app/models/__init__.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
"""
|
||||
SQLAlchemy Models Package
|
||||
"""
|
||||
from app.models.domain import Domain
|
||||
from app.models.whois import WhoisRecord
|
||||
from app.models.dns import DnsRecord
|
||||
from app.models.ssl import SslCertificate
|
||||
from app.models.reputation import ReputationScore
|
||||
from app.models.risk import RiskAssessment
|
||||
from app.models.check_history import CheckHistory
|
||||
from app.models.batch import BatchOperation
|
||||
from app.models.blacklist import Blacklist
|
||||
from app.models.api_usage import ApiUsageLog
|
||||
|
||||
__all__ = [
|
||||
'Domain',
|
||||
'WhoisRecord',
|
||||
'DnsRecord',
|
||||
'SslCertificate',
|
||||
'ReputationScore',
|
||||
'RiskAssessment',
|
||||
'CheckHistory',
|
||||
'BatchOperation',
|
||||
'Blacklist',
|
||||
'ApiUsageLog'
|
||||
]
|
||||
32
ai_platform/modules/domain_check/api/app/models/api_usage.py
Normal file
32
ai_platform/modules/domain_check/api/app/models/api_usage.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""API Usage Log Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class ApiUsageLog(db.Model):
|
||||
"""API usage logging model"""
|
||||
__tablename__ = 'api_usage_logs'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
service_name = db.Column(db.String(50), nullable=False, index=True)
|
||||
endpoint = db.Column(db.String(255))
|
||||
request_count = db.Column(db.Integer, default=1)
|
||||
response_time_ms = db.Column(db.Integer)
|
||||
status_code = db.Column(db.Integer, index=True)
|
||||
quota_used = db.Column(db.Integer)
|
||||
quota_remaining = db.Column(db.Integer)
|
||||
error_message = db.Column(db.Text)
|
||||
request_params = db.Column(JSONB)
|
||||
logged_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'service_name': self.service_name,
|
||||
'endpoint': self.endpoint,
|
||||
'status_code': self.status_code,
|
||||
'response_time_ms': self.response_time_ms,
|
||||
'logged_at': self.logged_at.isoformat() if self.logged_at else None
|
||||
}
|
||||
39
ai_platform/modules/domain_check/api/app/models/batch.py
Normal file
39
ai_platform/modules/domain_check/api/app/models/batch.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
"""Batch Operation Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, ARRAY, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class BatchOperation(db.Model):
|
||||
"""Batch operation model"""
|
||||
__tablename__ = 'batch_operations'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
batch_id = db.Column(UUID(as_uuid=True), unique=True, nullable=False, index=True)
|
||||
total_domains = db.Column(db.Integer, nullable=False)
|
||||
completed_count = db.Column(db.Integer, default=0)
|
||||
failed_count = db.Column(db.Integer, default=0)
|
||||
status = db.Column(db.String(20), default='pending', index=True)
|
||||
priority = db.Column(db.String(20), default='normal', index=True)
|
||||
started_at = db.Column(db.DateTime(timezone=True))
|
||||
completed_at = db.Column(db.DateTime(timezone=True))
|
||||
estimated_completion_at = db.Column(db.DateTime(timezone=True))
|
||||
requested_by = db.Column(db.String(100))
|
||||
check_options = db.Column(JSONB)
|
||||
domain_list = db.Column(ARRAY(db.Text))
|
||||
error_log = db.Column(JSONB)
|
||||
summary = db.Column(JSONB)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'batch_id': str(self.batch_id),
|
||||
'total_domains': self.total_domains,
|
||||
'completed_count': self.completed_count,
|
||||
'failed_count': self.failed_count,
|
||||
'status': self.status,
|
||||
'progress_percentage': round((self.completed_count / self.total_domains * 100) if self.total_domains > 0 else 0, 2),
|
||||
'started_at': self.started_at.isoformat() if self.started_at else None,
|
||||
'completed_at': self.completed_at.isoformat() if self.completed_at else None
|
||||
}
|
||||
33
ai_platform/modules/domain_check/api/app/models/blacklist.py
Normal file
33
ai_platform/modules/domain_check/api/app/models/blacklist.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""Blacklist Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class Blacklist(db.Model):
|
||||
"""Blacklist model"""
|
||||
__tablename__ = 'blacklists'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain = db.Column(db.String(255), unique=True, nullable=False, index=True)
|
||||
reason = db.Column(db.Text)
|
||||
category = db.Column(db.String(50), index=True)
|
||||
source = db.Column(db.String(100))
|
||||
severity = db.Column(db.String(20), default='medium', index=True)
|
||||
added_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
is_active = db.Column(db.Boolean, default=True, index=True)
|
||||
expires_at = db.Column(db.DateTime(timezone=True))
|
||||
extra_data = db.Column(JSONB)
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'domain': self.domain,
|
||||
'reason': self.reason,
|
||||
'category': self.category,
|
||||
'severity': self.severity,
|
||||
'is_active': self.is_active,
|
||||
'added_at': self.added_at.isoformat() if self.added_at else None
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
"""Check History Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class CheckHistory(db.Model):
|
||||
"""Check history model"""
|
||||
__tablename__ = 'check_history'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
check_id = db.Column(UUID(as_uuid=True), unique=True, nullable=False, index=True)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
risk_assessment_id = db.Column(UUID(as_uuid=True), db.ForeignKey('risk_assessments.id', ondelete='SET NULL'))
|
||||
requested_by = db.Column(db.String(100), default='api', index=True)
|
||||
request_ip = db.Column(db.String(45))
|
||||
user_agent = db.Column(db.Text)
|
||||
check_options = db.Column(JSONB)
|
||||
processing_time_ms = db.Column(db.Integer)
|
||||
cache_hit = db.Column(db.Boolean, default=False)
|
||||
changes_detected = db.Column(db.Boolean, default=False)
|
||||
change_summary = db.Column(JSONB)
|
||||
status = db.Column(db.String(20), default='completed', index=True)
|
||||
error_message = db.Column(db.Text)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
|
||||
domain = db.relationship('Domain', back_populates='check_history')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'check_id': str(self.check_id),
|
||||
'status': self.status,
|
||||
'cache_hit': self.cache_hit,
|
||||
'processing_time_ms': self.processing_time_ms,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None
|
||||
}
|
||||
31
ai_platform/modules/domain_check/api/app/models/dns.py
Normal file
31
ai_platform/modules/domain_check/api/app/models/dns.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"""DNS Record Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from app import db
|
||||
|
||||
|
||||
class DnsRecord(db.Model):
|
||||
"""DNS record model"""
|
||||
__tablename__ = 'dns_records'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
record_type = db.Column(db.String(10), nullable=False, index=True)
|
||||
record_value = db.Column(db.Text, nullable=False)
|
||||
ttl = db.Column(db.Integer)
|
||||
priority = db.Column(db.Integer)
|
||||
fetched_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
domain = db.relationship('Domain', back_populates='dns_records')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'record_type': self.record_type,
|
||||
'record_value': self.record_value,
|
||||
'ttl': self.ttl,
|
||||
'priority': self.priority,
|
||||
'fetched_at': self.fetched_at.isoformat() if self.fetched_at else None
|
||||
}
|
||||
118
ai_platform/modules/domain_check/api/app/models/domain.py
Normal file
118
ai_platform/modules/domain_check/api/app/models/domain.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
"""
|
||||
Domain Model
|
||||
"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, ARRAY
|
||||
from app import db
|
||||
|
||||
|
||||
class Domain(db.Model):
|
||||
"""Domain model - stores basic domain information"""
|
||||
|
||||
__tablename__ = 'domains'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain = db.Column(db.String(255), nullable=False, index=True)
|
||||
subdomain = db.Column(db.String(255), nullable=True)
|
||||
tld = db.Column(db.String(50), nullable=False, index=True)
|
||||
full_domain = db.Column(db.String(255), unique=True, nullable=False, index=True)
|
||||
|
||||
first_seen_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
last_checked_at = db.Column(db.DateTime(timezone=True), nullable=True, index=True)
|
||||
check_count = db.Column(db.Integer, default=0)
|
||||
is_active = db.Column(db.Boolean, default=True, index=True)
|
||||
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
updated_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
# Relationships
|
||||
whois_records = db.relationship('WhoisRecord', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
dns_records = db.relationship('DnsRecord', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
ssl_certificates = db.relationship('SslCertificate', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
reputation_scores = db.relationship('ReputationScore', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
risk_assessments = db.relationship('RiskAssessment', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
check_history = db.relationship('CheckHistory', back_populates='domain', lazy='dynamic', cascade='all, delete-orphan')
|
||||
|
||||
def __repr__(self):
|
||||
return f'<Domain {self.full_domain}>'
|
||||
|
||||
def to_dict(self, include_relationships=False):
|
||||
"""Convert model to dictionary"""
|
||||
data = {
|
||||
'id': str(self.id),
|
||||
'domain': self.domain,
|
||||
'subdomain': self.subdomain,
|
||||
'tld': self.tld,
|
||||
'full_domain': self.full_domain,
|
||||
'first_seen_at': self.first_seen_at.isoformat() if self.first_seen_at else None,
|
||||
'last_checked_at': self.last_checked_at.isoformat() if self.last_checked_at else None,
|
||||
'check_count': self.check_count,
|
||||
'is_active': self.is_active,
|
||||
'created_at': self.created_at.isoformat() if self.created_at else None,
|
||||
'updated_at': self.updated_at.isoformat() if self.updated_at else None
|
||||
}
|
||||
|
||||
if include_relationships:
|
||||
# Get latest records
|
||||
latest_whois = self.whois_records.order_by(WhoisRecord.fetched_at.desc()).first()
|
||||
latest_risk = self.risk_assessments.order_by(RiskAssessment.assessed_at.desc()).first()
|
||||
|
||||
data['latest_whois'] = latest_whois.to_dict() if latest_whois else None
|
||||
data['latest_risk'] = latest_risk.to_dict() if latest_risk else None
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def parse_domain(full_domain: str) -> dict:
|
||||
"""
|
||||
Parse a full domain into components
|
||||
|
||||
Args:
|
||||
full_domain: Full domain name (e.g., 'www.example.com')
|
||||
|
||||
Returns:
|
||||
dict with 'domain', 'subdomain', 'tld', 'full_domain'
|
||||
"""
|
||||
import tldextract
|
||||
|
||||
extracted = tldextract.extract(full_domain)
|
||||
|
||||
return {
|
||||
'domain': extracted.domain,
|
||||
'subdomain': extracted.subdomain if extracted.subdomain else None,
|
||||
'tld': extracted.suffix,
|
||||
'full_domain': full_domain.lower().strip()
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_or_create(cls, full_domain: str):
|
||||
"""
|
||||
Get existing domain or create new one
|
||||
|
||||
Args:
|
||||
full_domain: Full domain name
|
||||
|
||||
Returns:
|
||||
Tuple of (Domain instance, created boolean)
|
||||
"""
|
||||
domain = cls.query.filter_by(full_domain=full_domain.lower()).first()
|
||||
|
||||
if domain:
|
||||
return domain, False
|
||||
|
||||
# Parse domain components
|
||||
parsed = cls.parse_domain(full_domain)
|
||||
|
||||
# Create new domain
|
||||
domain = cls(
|
||||
domain=parsed['domain'],
|
||||
subdomain=parsed['subdomain'],
|
||||
tld=parsed['tld'],
|
||||
full_domain=parsed['full_domain']
|
||||
)
|
||||
|
||||
db.session.add(domain)
|
||||
db.session.commit()
|
||||
|
||||
return domain, True
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
"""Reputation Score Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, ARRAY, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class ReputationScore(db.Model):
|
||||
"""Reputation score from various sources"""
|
||||
__tablename__ = 'reputation_scores'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
source = db.Column(db.String(50), nullable=False, index=True)
|
||||
score = db.Column(db.Integer)
|
||||
malicious_count = db.Column(db.Integer, default=0)
|
||||
suspicious_count = db.Column(db.Integer, default=0)
|
||||
harmless_count = db.Column(db.Integer, default=0)
|
||||
undetected_count = db.Column(db.Integer, default=0)
|
||||
is_blacklisted = db.Column(db.Boolean, default=False, index=True)
|
||||
blacklist_names = db.Column(ARRAY(db.Text))
|
||||
is_typosquatting = db.Column(db.Boolean, default=False, index=True)
|
||||
typosquatting_target = db.Column(db.String(255))
|
||||
raw_response = db.Column(JSONB)
|
||||
checked_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
domain = db.relationship('Domain', back_populates='reputation_scores')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'source': self.source,
|
||||
'score': self.score,
|
||||
'malicious_count': self.malicious_count,
|
||||
'suspicious_count': self.suspicious_count,
|
||||
'harmless_count': self.harmless_count,
|
||||
'is_blacklisted': self.is_blacklisted,
|
||||
'blacklist_names': self.blacklist_names,
|
||||
'is_typosquatting': self.is_typosquatting,
|
||||
'checked_at': self.checked_at.isoformat() if self.checked_at else None
|
||||
}
|
||||
43
ai_platform/modules/domain_check/api/app/models/risk.py
Normal file
43
ai_platform/modules/domain_check/api/app/models/risk.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
"""Risk Assessment Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class RiskAssessment(db.Model):
|
||||
"""Risk assessment model"""
|
||||
__tablename__ = 'risk_assessments'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
check_id = db.Column(UUID(as_uuid=True), unique=True, nullable=False, index=True)
|
||||
total_score = db.Column(db.Integer, nullable=False, index=True)
|
||||
risk_level = db.Column(db.String(20), nullable=False, index=True)
|
||||
domain_age_score = db.Column(db.Integer, default=0)
|
||||
domain_age_days = db.Column(db.Integer)
|
||||
ssl_score = db.Column(db.Integer, default=0)
|
||||
dns_score = db.Column(db.Integer, default=0)
|
||||
reputation_score = db.Column(db.Integer, default=0)
|
||||
whois_score = db.Column(db.Integer, default=0)
|
||||
factors = db.Column(JSONB)
|
||||
is_new_domain = db.Column(db.Boolean, default=False, index=True)
|
||||
is_suspicious = db.Column(db.Boolean, default=False, index=True)
|
||||
requires_manual_review = db.Column(db.Boolean, default=False)
|
||||
assessed_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
domain = db.relationship('Domain', back_populates='risk_assessments')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'check_id': str(self.check_id),
|
||||
'total_score': self.total_score,
|
||||
'risk_level': self.risk_level,
|
||||
'domain_age_days': self.domain_age_days,
|
||||
'is_new_domain': self.is_new_domain,
|
||||
'is_suspicious': self.is_suspicious,
|
||||
'factors': self.factors,
|
||||
'assessed_at': self.assessed_at.isoformat() if self.assessed_at else None
|
||||
}
|
||||
40
ai_platform/modules/domain_check/api/app/models/ssl.py
Normal file
40
ai_platform/modules/domain_check/api/app/models/ssl.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"""SSL Certificate Model"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class SslCertificate(db.Model):
|
||||
"""SSL Certificate model"""
|
||||
__tablename__ = 'ssl_certificates'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
issuer = db.Column(db.String(255), index=True)
|
||||
subject = db.Column(db.String(255))
|
||||
valid_from = db.Column(db.DateTime(timezone=True))
|
||||
valid_until = db.Column(db.DateTime(timezone=True), index=True)
|
||||
serial_number = db.Column(db.String(255))
|
||||
signature_algorithm = db.Column(db.String(100))
|
||||
key_size = db.Column(db.Integer)
|
||||
is_wildcard = db.Column(db.Boolean, default=False)
|
||||
is_self_signed = db.Column(db.Boolean, default=False)
|
||||
is_valid = db.Column(db.Boolean, default=True, index=True)
|
||||
certificate_chain = db.Column(JSONB)
|
||||
fetched_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
domain = db.relationship('Domain', back_populates='ssl_certificates')
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'issuer': self.issuer,
|
||||
'subject': self.subject,
|
||||
'valid_from': self.valid_from.isoformat() if self.valid_from else None,
|
||||
'valid_until': self.valid_until.isoformat() if self.valid_until else None,
|
||||
'is_valid': self.is_valid,
|
||||
'is_self_signed': self.is_self_signed,
|
||||
'days_until_expiry': (self.valid_until - datetime.utcnow()).days if self.valid_until and self.valid_until > datetime.utcnow() else 0
|
||||
}
|
||||
62
ai_platform/modules/domain_check/api/app/models/whois.py
Normal file
62
ai_platform/modules/domain_check/api/app/models/whois.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""
|
||||
WHOIS Record Model
|
||||
"""
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sqlalchemy.dialects.postgresql import UUID, ARRAY, JSONB
|
||||
from app import db
|
||||
|
||||
|
||||
class WhoisRecord(db.Model):
|
||||
"""WHOIS/RDAP record model"""
|
||||
|
||||
__tablename__ = 'whois_records'
|
||||
|
||||
id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
domain_id = db.Column(UUID(as_uuid=True), db.ForeignKey('domains.id', ondelete='CASCADE'), nullable=False, index=True)
|
||||
|
||||
creation_date = db.Column(db.DateTime(timezone=True), index=True)
|
||||
expiration_date = db.Column(db.DateTime(timezone=True))
|
||||
updated_date = db.Column(db.DateTime(timezone=True))
|
||||
|
||||
registrar = db.Column(db.String(255), index=True)
|
||||
registrar_url = db.Column(db.String(500))
|
||||
registrant_org = db.Column(db.String(255))
|
||||
registrant_country = db.Column(db.String(2))
|
||||
admin_email = db.Column(db.String(255))
|
||||
|
||||
name_servers = db.Column(ARRAY(db.Text))
|
||||
status = db.Column(ARRAY(db.Text))
|
||||
dnssec = db.Column(db.Boolean)
|
||||
|
||||
raw_whois_data = db.Column(JSONB)
|
||||
data_source = db.Column(db.String(50), default='rdap', index=True)
|
||||
fetched_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow, index=True)
|
||||
created_at = db.Column(db.DateTime(timezone=True), default=datetime.utcnow)
|
||||
|
||||
# Relationship
|
||||
domain = db.relationship('Domain', back_populates='whois_records')
|
||||
|
||||
def __repr__(self):
|
||||
return f'<WhoisRecord domain_id={self.domain_id} source={self.data_source}>'
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary"""
|
||||
return {
|
||||
'id': str(self.id),
|
||||
'domain_id': str(self.domain_id),
|
||||
'creation_date': self.creation_date.isoformat() if self.creation_date else None,
|
||||
'expiration_date': self.expiration_date.isoformat() if self.expiration_date else None,
|
||||
'updated_date': self.updated_date.isoformat() if self.updated_date else None,
|
||||
'registrar': self.registrar,
|
||||
'registrar_url': self.registrar_url,
|
||||
'registrant_org': self.registrant_org,
|
||||
'registrant_country': self.registrant_country,
|
||||
'admin_email': self.admin_email,
|
||||
'name_servers': self.name_servers,
|
||||
'status': self.status,
|
||||
'dnssec': self.dnssec,
|
||||
'data_source': self.data_source,
|
||||
'fetched_at': self.fetched_at.isoformat() if self.fetched_at else None,
|
||||
'age_days': (datetime.utcnow() - self.creation_date).days if self.creation_date else None
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue