first commit

This commit is contained in:
2026-01-16 22:20:18 +03:00
commit 5d437e5e28
56 changed files with 4463 additions and 0 deletions

167
monitor/models.py Normal file
View File

@@ -0,0 +1,167 @@
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from decimal import Decimal
class BitcoinPrice(models.Model):
"""
Stores historical Bitcoin price data.
"""
timestamp = models.DateTimeField(auto_now_add=True)
price_usd = models.DecimalField(max_digits=20, decimal_places=2)
volume = models.DecimalField(max_digits=30, decimal_places=2, null=True, blank=True)
market_cap = models.DecimalField(max_digits=30, decimal_places=2, null=True, blank=True)
def __str__(self):
return f"Bitcoin: ${self.price_usd} at {self.timestamp.strftime('%Y-%m-%d %H:%M')}"
class Meta:
ordering = ['-timestamp'] # Newest first
class MarketAnalysis(models.Model):
"""
Stores market analysis results.
"""
STATUS_CHOICES = [
('dip', 'Dip'),
('peak', 'Peak'),
('neutral', 'Neutral'),
]
timestamp = models.DateTimeField(auto_now_add=True)
period = models.CharField(max_length=10, choices=[
('hourly', 'Hourly'),
('daily', 'Daily'),
('weekly', 'Weekly'),
('yearly', 'Yearly'),
], default='hourly')
# Price statistics
current_price = models.DecimalField(max_digits=20, decimal_places=2)
average_price = models.DecimalField(max_digits=20, decimal_places=2)
min_price = models.DecimalField(max_digits=20, decimal_places=2)
max_price = models.DecimalField(max_digits=20, decimal_places=2)
# Analysis results
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='neutral')
threshold_percent = models.DecimalField(
max_digits=5,
decimal_places=2,
default=15.0,
validators=[MinValueValidator(Decimal('0.01')), MaxValueValidator(Decimal('100'))]
)
# Calculated thresholds
lower_threshold = models.DecimalField(max_digits=20, decimal_places=2)
upper_threshold = models.DecimalField(max_digits=20, decimal_places=2)
# Event tracking
is_event = models.BooleanField(default=False)
event_type = models.CharField(max_length=20, blank=True, choices=[
('dip_below', 'Dip Below Threshold'),
('rise_above', 'Rise Above Threshold'),
('neutralized', 'Neutralized'),
])
def __str__(self):
return f"Analysis: {self.status.upper()} at ${self.current_price}"
class Meta:
ordering = ['-timestamp']
verbose_name_plural = "Market Analyses"
class SystemStatus(models.Model):
"""
Tracks system health and status for monitoring.
"""
timestamp = models.DateTimeField(auto_now_add=True)
# Update status
last_hourly_update = models.DateTimeField(null=True, blank=True)
last_successful_fetch = models.DateTimeField(null=True, blank=True)
# Current status
current_price = models.DecimalField(
max_digits=20, decimal_places=2, null=True, blank=True
)
# Error tracking
last_error = models.TextField(blank=True)
is_stale = models.BooleanField(default=True)
is_healthy = models.BooleanField(default=True)
class Meta:
ordering = ['-timestamp']
verbose_name_plural = "System Statuses"
def __str__(self):
status = "Healthy" if self.is_healthy else "Unhealthy"
return f"System Status: {status} at {self.timestamp}"
class NotificationPreference(models.Model):
"""
Stores notification preferences for each email address.
"""
email_address = models.EmailField(unique=True)
receive_event_alerts = models.BooleanField(
default=True,
help_text="Receive immediate alerts for threshold events"
)
receive_system_alerts = models.BooleanField(
default=True,
help_text="Receive alerts for system failures and issues"
)
receive_daily_digest = models.BooleanField(
default=True,
help_text="Receive daily summary email at 8 AM"
)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.email_address} (Active: {self.is_active})"
class Meta:
ordering = ['-created_at']
class EmailNotification(models.Model):
"""
Records of all emails sent by the system.
"""
NOTIFICATION_TYPES = [
('event', 'Event Alert'),
('system', 'System Alert'),
('digest', 'Daily Digest'),
('test', 'Test Email'),
]
STATUS_CHOICES = [
('pending', 'Pending'),
('sent', 'Sent'),
('failed', 'Failed'),
('retrying', 'Retrying'),
]
recipient = models.EmailField()
subject = models.CharField(max_length=255)
notification_type = models.CharField(max_length=20, choices=NOTIFICATION_TYPES)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
content_html = models.TextField(blank=True)
content_text = models.TextField(blank=True)
error_message = models.TextField(blank=True)
sent_at = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
retry_count = models.IntegerField(default=0)
def __str__(self):
return f"{self.notification_type} to {self.recipient} - {self.status}"
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['recipient', 'created_at']),
models.Index(fields=['notification_type', 'status']),
]