fix duplicated email
This commit is contained in:
@@ -2,6 +2,7 @@ from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils import timezone
|
||||
from django.db import transaction
|
||||
from settingspanel.models import AppSettings
|
||||
# from accounts.utils import JellyfinClient # not needed for availability; use Sonarr/Radarr instead
|
||||
import requests
|
||||
@@ -254,21 +255,31 @@ def check_and_notify_users():
|
||||
if season is None or number is None:
|
||||
continue
|
||||
|
||||
# duplicate guard (per series per day per user)
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
already_notified = SentNotification.objects.filter(
|
||||
media_id=sub.series_id,
|
||||
media_type='series',
|
||||
air_date=today,
|
||||
user=sub.user
|
||||
).exists()
|
||||
if already_notified:
|
||||
continue
|
||||
|
||||
# check availability via Sonarr hasFile
|
||||
if sonarr_episode_has_file(sub.series_id, season, number):
|
||||
if not sub.user.email:
|
||||
continue
|
||||
# After confirming availability, reserve once per user/series/day
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
try:
|
||||
with transaction.atomic():
|
||||
obj, created = SentNotification.objects.get_or_create(
|
||||
user=sub.user,
|
||||
media_id=sub.series_id,
|
||||
media_type='series',
|
||||
air_date=today,
|
||||
defaults={
|
||||
'media_title': sub.series_title,
|
||||
}
|
||||
)
|
||||
if not created:
|
||||
# already reserved/sent
|
||||
continue
|
||||
except Exception:
|
||||
# if DB error (race), skip to avoid duplicates
|
||||
continue
|
||||
|
||||
try:
|
||||
send_notification_email(
|
||||
user=sub.user,
|
||||
media_title=sub.series_title,
|
||||
@@ -280,15 +291,20 @@ def check_and_notify_users():
|
||||
episode=number,
|
||||
air_date=ep.get('airDateUtc'),
|
||||
)
|
||||
# mark as sent unless duplicates are allowed
|
||||
except Exception:
|
||||
# roll back reservation so we can retry next run
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
SentNotification.objects.create(
|
||||
try:
|
||||
SentNotification.objects.filter(
|
||||
user=sub.user,
|
||||
media_id=sub.series_id,
|
||||
media_type='series',
|
||||
media_title=sub.series_title,
|
||||
air_date=today
|
||||
)
|
||||
air_date=today,
|
||||
).delete()
|
||||
except Exception:
|
||||
pass
|
||||
continue
|
||||
# no-op: already reserved via get_or_create above
|
||||
|
||||
# Film-Abos
|
||||
for sub in MovieSubscription.objects.select_related('user').all():
|
||||
@@ -296,16 +312,6 @@ def check_and_notify_users():
|
||||
if not it:
|
||||
continue
|
||||
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
already_notified = SentNotification.objects.filter(
|
||||
media_id=sub.movie_id,
|
||||
media_type='movie',
|
||||
air_date=today,
|
||||
user=sub.user
|
||||
).exists()
|
||||
if already_notified:
|
||||
continue
|
||||
|
||||
if radarr_movie_has_file(sub.movie_id):
|
||||
if not sub.user.email:
|
||||
continue
|
||||
@@ -323,6 +329,25 @@ def check_and_notify_users():
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# After confirming availability, reserve once per user/movie/day
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
try:
|
||||
with transaction.atomic():
|
||||
obj, created = SentNotification.objects.get_or_create(
|
||||
user=sub.user,
|
||||
media_id=sub.movie_id,
|
||||
media_type='movie',
|
||||
air_date=today,
|
||||
defaults={
|
||||
'media_title': sub.title,
|
||||
}
|
||||
)
|
||||
if not created:
|
||||
continue
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
try:
|
||||
send_notification_email(
|
||||
user=sub.user,
|
||||
media_title=sub.title,
|
||||
@@ -332,14 +357,19 @@ def check_and_notify_users():
|
||||
year=it.get('year'),
|
||||
release_type=rel,
|
||||
)
|
||||
except Exception:
|
||||
if not getattr(settings, 'NOTIFICATIONS_ALLOW_DUPLICATES', False):
|
||||
SentNotification.objects.create(
|
||||
try:
|
||||
SentNotification.objects.filter(
|
||||
user=sub.user,
|
||||
media_id=sub.movie_id,
|
||||
media_type='movie',
|
||||
media_title=sub.title,
|
||||
air_date=today
|
||||
)
|
||||
air_date=today,
|
||||
).delete()
|
||||
except Exception:
|
||||
pass
|
||||
continue
|
||||
# no-op: already reserved via get_or_create above
|
||||
|
||||
|
||||
def has_new_episode_today(series_id):
|
||||
|
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.5 on 2025-08-13 19:06
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('settingspanel', '0003_alter_appsettings_mail_secure'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='appsettings',
|
||||
name='mail_secure',
|
||||
field=models.CharField(blank=True, choices=[('', 'No TLS/SSL'), ('starttls', 'STARTTLS (Port 587)'), ('ssl', 'SSL/TLS (Port 465)'), ('tls', 'TLS (alias STARTTLS)')], max_length=10, null=True),
|
||||
),
|
||||
]
|
@@ -183,4 +183,5 @@ DEFAULT_FROM_EMAIL = None # Will be set from AppSettings
|
||||
|
||||
# Notifications / Debug
|
||||
# If True, duplicate suppression is disabled and emails can be resent on every run.
|
||||
NOTIFICATIONS_ALLOW_DUPLICATES = os.getenv('NOTIFICATIONS_ALLOW_DUPLICATES', 'True').lower() == 'true'
|
||||
# Default is False to avoid accidental duplicate mails in local/dev runs.
|
||||
NOTIFICATIONS_ALLOW_DUPLICATES = os.getenv('NOTIFICATIONS_ALLOW_DUPLICATES', 'False').lower() == 'true'
|
||||
|
Reference in New Issue
Block a user