3 Commits
403e068475
...
480f9113ff
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
480f9113ff |
otp updated for dovodi
|
2 hours ago |
|
|
db03332ec5 |
better and smarter way to show source volumes and edditions with has edditions switch
|
2 hours ago |
|
|
4d24052fdf |
source author avatar field added
|
21 hours ago |
7 changed files with 136 additions and 28 deletions
-
18apps/hadis/migrations/0034_bookauthor_image.py
-
18apps/hadis/migrations/0035_bookreference_has_editions.py
-
13apps/hadis/models/reference.py
-
22apps/hadis/serializers/reference_v2.py
-
34apps/hadis/serializers/serializers_admin.py
-
6config/settings/base.py
-
53utils/__init__.py
@ -0,0 +1,18 @@ |
|||
# Generated by Django 4.2.30 on 2026-08-23 16:19 |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('hadis', '0033_bookeditor'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='bookauthor', |
|||
name='image', |
|||
field=models.ImageField(blank=True, help_text='image allowed', null=True, upload_to='hadis/author_images/', verbose_name='Image'), |
|||
), |
|||
] |
|||
@ -0,0 +1,18 @@ |
|||
# Generated by Django 4.2.30 on 2026-08-24 10:29 |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('hadis', '0034_bookauthor_image'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AddField( |
|||
model_name='bookreference', |
|||
name='has_editions', |
|||
field=models.BooleanField(default=False, help_text='True if this reference has one or more editions, False for direct volumes without edition structure', verbose_name='Has Editions Structure'), |
|||
), |
|||
] |
|||
@ -105,10 +105,8 @@ REDIS_URL = env('REDIS_URL') |
|||
|
|||
|
|||
|
|||
OTP_SERIVCE_KEY = "33213d78f1234e99b81f94eefda77e45" |
|||
|
|||
RESEND_API_KEY = "re_JFFAfESy_JHmJTJLu5ToGTPhwrZx7trKd" |
|||
RESEND_FROM_EMAIL = "[email protected]" |
|||
RESEND_API_KEY = env('RESEND_API_KEY', default="re_JFFAfESy_JHmJTJLu5ToGTPhwrZx7trKd") |
|||
RESEND_FROM_EMAIL = env('RESEND_FROM_EMAIL', default="Dovodi <[email protected]>") |
|||
|
|||
|
|||
PHONENUMBER_DEFAULT_REGION = "IR" |
|||
|
|||
@ -90,22 +90,38 @@ def environment_callback(request): |
|||
return [_("Production"), "primary"] |
|||
|
|||
|
|||
|
|||
def send_email(recipient, code): |
|||
import requests |
|||
from django.conf import settings |
|||
|
|||
if not getattr(settings, "RESEND_API_KEY", None): |
|||
api_key = getattr(settings, "RESEND_API_KEY", None) |
|||
if not api_key: |
|||
logger.warning("RESEND_API_KEY is not set in settings.") |
|||
return False |
|||
|
|||
url = "https://api.resend.com/emails" |
|||
headers = { |
|||
"Authorization": f"Bearer {settings.RESEND_API_KEY}", |
|||
"Authorization": f"Bearer {api_key}", |
|||
"Content-Type": "application/json", |
|||
} |
|||
|
|||
site_domain = getattr(settings, "SITE_DOMAIN", "https://dovodi.newhorizonco.uk/") |
|||
# Normalize recipient into a clean list of email strings |
|||
if isinstance(recipient, str): |
|||
to_emails = [recipient.strip()] |
|||
elif isinstance(recipient, (list, tuple, set)): |
|||
to_emails = [str(r).strip() for r in recipient if r and str(r).strip()] |
|||
else: |
|||
to_emails = [str(recipient).strip()] |
|||
|
|||
if not to_emails: |
|||
logger.error(f"Cannot send email: recipient list is empty ({recipient})") |
|||
return False |
|||
|
|||
from_email = getattr(settings, "RESEND_FROM_EMAIL", "Dovodi <[email protected]>") |
|||
if "<" not in from_email and "@" in from_email: |
|||
from_email = f"Dovodi <{from_email}>" |
|||
|
|||
site_domain = getattr(settings, "SITE_DOMAIN", "https://dovodi.newhorizonco.uk/").rstrip('/') |
|||
subject = "Код подтверждения | Verification Code" |
|||
|
|||
html_content = f""" |
|||
@ -128,7 +144,7 @@ def send_email(recipient, code): |
|||
<!-- Header with Logo --> |
|||
<tr> |
|||
<td style="padding: 32px 32px 20px 32px; text-align: center; background-color: #FAFAFC; border-bottom: 1px solid #F1F3F7;"> |
|||
<img src="{site_domain}/static/images/dovoodi_logo.svg" alt="Dovodi Logo" style="height: 38px; width: auto; max-width: 160px; display: inline-block;" /> |
|||
<img src="{site_domain}/static/images/dovoodi_logo.svg" alt="Dovodi" style="height: 38px; width: auto; max-width: 160px; display: inline-block;" /> |
|||
</td> |
|||
</tr> |
|||
<!-- Main Body Section --> |
|||
@ -148,7 +164,7 @@ def send_email(recipient, code): |
|||
|
|||
<!-- Intro Message --> |
|||
<p style="margin: 0 0 24px 0; font-size: 14px; color: #646A75; text-align: center; line-height: 1.6;"> |
|||
Используйте следующий одноразовый код для входа или подтверждения учетной записи в <strong>Dovodi</strong>: |
|||
Используйте следующий одноразовый код для входа یا подтверждения учетной записи в <strong>Dovodi</strong>: |
|||
</p> |
|||
|
|||
<!-- OTP Box --> |
|||
@ -183,7 +199,7 @@ def send_email(recipient, code): |
|||
<p style="margin: 0 0 12px 0; font-size: 12px; color: #646A75;"> |
|||
<a href="https://dovodi.newhorizonco.uk/" style="color: #5172E1; text-decoration: none; font-weight: 600;">dovodi.newhorizonco.uk</a> |
|||
• |
|||
<a href="mailto:[EMAIL_ADDRESS]" style="color: #5172E1; text-decoration: none; font-weight: 600;">[EMAIL_ADDRESS]</a> |
|||
<a href="mailto:[email protected]" style="color: #5172E1; text-decoration: none; font-weight: 600;">info@imamjavad.online</a> |
|||
</p> |
|||
<p style="margin: 0; font-size: 11px; color: #9AA0AC; line-height: 1.4;"> |
|||
© 2026 Dovodi. Все права защищены. |
|||
@ -197,20 +213,33 @@ def send_email(recipient, code): |
|||
</body> |
|||
</html> |
|||
""" |
|||
|
|||
text_content = ( |
|||
f"Код подтверждения Dovodi: {code}\n\n" |
|||
f"Your Dovodi verification code is: {code}\n\n" |
|||
f"Срок действия кода истекает через 5 минут. Если вы не запрашивали этот код, проигнорируйте это письмо.\n" |
|||
f"Никому не передавайте этот код в целях безопасности вашего аккаунта." |
|||
) |
|||
|
|||
payload = { |
|||
"from": settings.RESEND_FROM_EMAIL, |
|||
"to": recipient, |
|||
"from": from_email, |
|||
"to": to_emails, |
|||
"subject": subject, |
|||
"html": html_content, |
|||
"text": text_content, |
|||
} |
|||
|
|||
try: |
|||
response = requests.post(url, headers=headers, json=payload) |
|||
response.raise_for_status() |
|||
response = requests.post(url, headers=headers, json=payload, timeout=15) |
|||
if response.status_code >= 400: |
|||
logger.error(f"Failed to send email via Resend: HTTP {response.status_code} - {response.text}") |
|||
print(f"Failed to send email via Resend: HTTP {response.status_code} - {response.text}") |
|||
return False |
|||
logger.info(f"Email OTP sent successfully via Resend to {to_emails}") |
|||
return True |
|||
except Exception as e: |
|||
logger.error(f"Failed to send email via Resend: {str(e)}") |
|||
logger.error(f"Failed to send email via Resend: {str(e)}", exc_info=True) |
|||
print(f"Failed to send email via Resend: {str(e)}") |
|||
return False |
|||
|
|||
|
|||
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue