Skip to content

Commit

Permalink
saving
Browse files Browse the repository at this point in the history
  • Loading branch information
KlemenSpruk committed Nov 20, 2023
1 parent 66b3e25 commit 352eda4
Show file tree
Hide file tree
Showing 16 changed files with 66 additions and 66 deletions.
5 changes: 4 additions & 1 deletion django_project_base/celery/background_tasks/base_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class BaseTask(app.Task):
settings: Optional[Settings] = None

def before_start(self, task_id, args, kwargs):
if (path := self._app.conf.get('django-settings-module')) and len(path):
if (path := self._app.conf.get("django-settings-module")) and len(path):
self.settings = Settings(path)
db_settings: dict = self.settings.DATABASES["default"]
db_settings.setdefault("TIME_ZONE", None)
Expand All @@ -40,3 +40,6 @@ def on_failure(self, exc, task_id, args, kwargs, einfo):
logging.getLogger(__name__).error(
f"Exception: {exc} \n\nTask id: {task_id}\n\nArgs: {args}\n\nKwargs: {kwargs}\n\nEInfo: {einfo}"
)

def run(self, *args, **kwargs):
return None
5 changes: 2 additions & 3 deletions django_project_base/celery/background_tasks/beat_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from django_project_base.celery.background_tasks.base_task import BaseTask
from django_project_base.celery.celery import app
from django_project_base.constants import NOTIFICATION_QUEUE_NAME
from django_project_base.notifications.base.send_notification_mixin import SendNotificationMixin
from django_project_base.notifications.models import DjangoProjectBaseNotification


Expand All @@ -28,15 +27,15 @@ def run(self):

# SET CONNECTION AND DELETE IT IN EXTRA DATA
for notification in DjangoProjectBaseNotification.objects.using(NOTIFICATION_QUEUE_NAME).filter(
send_at__isnull=False, sent_at__isnull=True, send_at__lte=now_ts
send_at__isnull=False, sent_at__isnull=True, send_at__lte=now_ts
):
notification.email_fallback = notification.extra_data["mail-fallback"]
notification.user = notification.extra_data["user"]
notification.recipients_list = notification.extra_data["recipients-list"]
notification.sender = notification.extra_data["sender"]
print(notification)

# SendNotificationMixin().make_send(notification, notification.extra_data or {}, resend=False)
# SendNotificationService().make_send(notification, notification.extra_data or {}, resend=False)
self._clear_in_progress_status()

def on_failure(self, exc, task_id, args, kwargs, einfo):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django_project_base.celery.background_tasks.base_task import BaseTask
from django_project_base.celery.celery import app
from django_project_base.celery.settings import NOTIFICATION_QUEABLE_HARD_TIME_LIMIT, NOTIFICATION_SEND_PAUSE_SECONDS
from django_project_base.notifications.base.send_notification_mixin import SendNotificationMixin
from django_project_base.notifications.base.send_notification_service import SendNotificationService

LAST_MAIL_SENT_CK = "last-notification-was-sent-timestamp"

Expand All @@ -26,12 +26,12 @@ def run(self, notification: "DjangoProjectBaseNotification", extra_data): # noq
time_from_last_sent: float = time.time() - last_sent if last_sent else 0
if time_from_last_sent < NOTIFICATION_SEND_PAUSE_SECONDS:
time.sleep(int(NOTIFICATION_SEND_PAUSE_SECONDS - time_from_last_sent))
SendNotificationMixin().make_send(notification=notification, extra_data=extra_data)
SendNotificationService(settings=self.settings).make_send(notification=notification, extra_data=extra_data)
finally:
cache.set(LAST_MAIL_SENT_CK, time.time(), timeout=NOTIFICATION_SEND_PAUSE_SECONDS + 1)

def on_failure(self, exc, task_id, args, kwargs, einfo):
super().on_failure(exc=exc, task_id=task_id, args=args, kwargs=kwargs)
super().on_failure(exc=exc, task_id=task_id, args=args, kwargs=kwargs, einfo=einfo)


send_notification_task = app.register_task(SendNotificationTask())
7 changes: 4 additions & 3 deletions django_project_base/notifications/base/channels/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,17 @@ def _find_provider(
exclude = []

def get_first_provider(val: Union[str, List]):
print("PROVIDER", val, setting_name, settings)
if val and isinstance(val, (list, tuple)):
prov = next(filter(lambda i: i not in exclude, val), None)

return import_string(prov)() if prov else None

return import_string(val)() if val not in exclude else None
return import_string(val)() if val not in exclude and val else None

if settings and getattr(settings, setting_name, None):
return get_first_provider(settings.setting_name)
return get_first_provider(getattr(settings, setting_name, ""))
return get_first_provider(getattr(settings, setting_name))
return get_first_provider(getattr(settings or object(), setting_name, ""))

def clean_recipients(self, recipients: List[Recipient]) -> List[Recipient]:
return list(set(recipients))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Union
from typing import Union, Optional

import boto3
from django.conf import settings
from django.conf import settings, Settings
from rest_framework.status import is_success

from django_project_base.notifications.base.channels.channel import Recipient
Expand Down Expand Up @@ -30,18 +30,13 @@ def validate_send(self, response: dict):
def _get_sms_message(self, notification: DjangoProjectBaseNotification) -> Union[dict, str]:
return super()._get_sms_message(notification)

def ensure_credentials(self, extra_data):
def ensure_credentials(self, settings: Optional[Settings] = None):
if settings and getattr(settings, "TESTING", False):
return
self.key_id = getattr(settings, "NOTIFICATIONS_AWS_SES_ACCESS_KEY_ID", None)
self.access_key = getattr(settings, "NOTIFICATIONS_AWS_SES_SECRET_ACCESS_KEY", None)
self.region = getattr(settings, "NOTIFICATIONS_AWS_SES_REGION_NAME", None)
self.settings = settings
if extra_data and (stgs := extra_data.get("SETTINGS")):
self.settings = stgs
self.key_id = getattr(stgs, "NOTIFICATIONS_AWS_SES_ACCESS_KEY_ID", None)
self.access_key = getattr(stgs, "NOTIFICATIONS_AWS_SES_SECRET_ACCESS_KEY", None)
self.region = getattr(stgs, "NOTIFICATIONS_AWS_SES_REGION_NAME", None)
assert self.key_id, "AWS SES key id required"
assert self.access_key, "AWS SES key id access key required"
assert self.region, "AWS SES region required"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Union
from typing import Union, Optional

import boto3
from django.conf import settings
from django.conf import settings, Settings
from rest_framework.status import is_success

from django_project_base.notifications.base.channels.channel import Recipient
Expand All @@ -17,18 +17,13 @@ class AwsSnsSingleSMS(ProviderIntegration):
def __init__(self) -> None:
super().__init__(settings=object())

def ensure_credentials(self, extra_data):
def ensure_credentials(self, settings: Optional[Settings] = None):
if settings and getattr(settings, "TESTING", False):
return
self.key_id = getattr(settings, "NOTIFICATIONS_AWS_SES_ACCESS_KEY_ID", None)
self.access_key = getattr(settings, "NOTIFICATIONS_AWS_SES_SECRET_ACCESS_KEY", None)
self.region = getattr(settings, "NOTIFICATIONS_AWS_SES_REGION_NAME", None)
self.settings = settings
if extra_data and (stgs := extra_data.get("SETTINGS")):
self.settings = stgs
self.key_id = getattr(stgs, "NOTIFICATIONS_AWS_SES_ACCESS_KEY_ID", None)
self.access_key = getattr(stgs, "NOTIFICATIONS_AWS_SES_SECRET_ACCESS_KEY", None)
self.region = getattr(stgs, "NOTIFICATIONS_AWS_SES_REGION_NAME", None)
assert self.key_id, "AWS SES key id required"
assert self.access_key, "AWS SES key id access key required"
assert self.region, "AWS SES region required"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Union
from typing import Union, Optional

import requests
from django.conf import settings
from django.conf import settings, Settings
from rest_framework.status import is_success

from django_project_base.notifications.base.channels.channel import Recipient
Expand All @@ -17,16 +17,12 @@ class NexmoSMS(ProviderIntegration):
def __init__(self) -> None:
super().__init__(settings=object())

def ensure_credentials(self, extra_data):
def ensure_credentials(self, settings: Optional[Settings] = None):
if settings and getattr(settings, "TESTING", False):
return
self.api_key = getattr(settings, "NEXMO_API_KEY", None)
self.api_secret = getattr(settings, "NEXMO_API_SECRET", None)
self.settings = settings
if extra_data and (stgs := extra_data.get("SETTINGS")):
self.settings = stgs
self.api_key = getattr(stgs, "NEXMO_API_KEY", None)
self.api_secret = getattr(stgs, "NEXMO_API_SECRET", None)
assert self.api_key, "NEXMO_API_KEY required"
assert self.api_secret, "NEXMO_API_SECRET required"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import re
from abc import ABC, abstractmethod
from html import unescape
from typing import Union
from typing import Union, Optional

import swapper
from django.conf import Settings
from django.urls import reverse
from django.utils.html import strip_tags

Expand All @@ -12,20 +13,20 @@


class ProviderIntegration(ABC):
settings: object
settings: Settings

is_sms_provider = True

def __init__(self, settings: object) -> None:
super().__init__()
self.settings = settings
self.settings = Settings

@abstractmethod
def validate_send(self, response: dict):
pass

@abstractmethod
def ensure_credentials(self, extra_data: dict):
def ensure_credentials(self, settings: Optional[Settings] = None):
pass

@abstractmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import json
from typing import Union
from typing import Union, Optional

import requests
import swapper
from django.conf import settings
from django.conf import settings, Settings
from django.contrib.auth import get_user_model
from requests.auth import HTTPBasicAuth
from rest_framework.status import is_success
Expand Down Expand Up @@ -277,18 +277,13 @@ class T2(ProviderIntegration):
def __init__(self) -> None:
super().__init__(settings=object())

def ensure_credentials(self, extra_data):
def ensure_credentials(self, settings: Optional[Settings] = None):
if settings and getattr(settings, "TESTING", False):
return
self.username = getattr(settings, "NOTIFICATIONS_T2_USERNAME", None)
self.password = getattr(settings, "NOTIFICATIONS_T2_PASSWORD", None)
self.url = getattr(settings, "NOTIFICATIONS_SMS_API_URL", None)
self.settings = settings
if extra_data and (stgs := extra_data.get("SETTINGS")):
self.settings = stgs
self.username = getattr(stgs, "NOTIFICATIONS_T2_USERNAME", None)
self.password = getattr(stgs, "NOTIFICATIONS_T2_PASSWORD", None)
self.url = getattr(stgs, "NOTIFICATIONS_SMS_API_URL", None)
assert self.username, "NOTIFICATIONS_T2_USERNAME is required"
assert self.password, "NOTIFICATIONS_T2_PASSWORD is required"
assert len(self.url) > 0, "NOTIFICATIONS_T2_PASSWORD is required"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class MailChannel(Channel):

notification_price = 0.0002 # TODO get from settings

provider_setting_name = "EMAIL_PROVIDER"
provider_setting_name = "NOTIFICATIONS_EMAIL_PROVIDER"

def send(self, notification: DjangoProjectBaseNotification, extra_data, **kwargs) -> int:
if getattr(settings, "TESTING", False):
Expand Down
2 changes: 1 addition & 1 deletion django_project_base/notifications/base/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def channel(
)
if channel:
channel.provider = channel._find_provider(settings=settings, setting_name=channel.provider_setting_name)
channel.provider.ensure_credentials(extra_data=extra_data)
channel.provider.ensure_credentials(settings=settings)
channel.provider.ensure_dlr_user(project_slug) if ensure_dlr_user else False

return channel
Expand Down
19 changes: 11 additions & 8 deletions django_project_base/notifications/base/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import List, Optional, Type

import swapper
from django.conf import settings
from django.conf import settings, Settings
from django.contrib.auth import get_user_model

from django_project_base.constants import (
Expand All @@ -16,11 +16,11 @@
from django_project_base.notifications.base.duplicate_notification_mixin import DuplicateNotificationMixin
from django_project_base.notifications.base.enums import ChannelIdentifier, NotificationLevel, NotificationType
from django_project_base.notifications.base.queable_notification_mixin import QueableNotificationMixin
from django_project_base.notifications.base.send_notification_mixin import SendNotificationMixin
from django_project_base.notifications.base.send_notification_service import SendNotificationService
from django_project_base.notifications.models import DjangoProjectBaseMessage, DjangoProjectBaseNotification


class Notification(QueableNotificationMixin, DuplicateNotificationMixin, SendNotificationMixin):
class Notification(QueableNotificationMixin, DuplicateNotificationMixin):
_persist = False
_delay = None
_recipients = []
Expand Down Expand Up @@ -112,7 +112,7 @@ def resend(notification: DjangoProjectBaseNotification, user_pk: Optional[str] =
)
notification.email_fallback = mail_fallback
notification.save(update_fields=["recipients", "recipients_original_payload_search"])
SendNotificationMixin().make_send(notification, notification.extra_data or {}, resend=True)
SendNotificationService(settings=settings).make_send(notification, notification.extra_data or {}, resend=True)

def __set_via_channels(self, val):
self._via_channels = val
Expand Down Expand Up @@ -178,7 +178,7 @@ def send(self) -> DjangoProjectBaseNotification:
extra_data=self._extra_data,
)

notification = self._ensure_channels(required_channels, notification)
notification = self._ensure_channels(channels=required_channels, notification=notification, settings=settings)

required_channels.sort()
if self.persist:
Expand Down Expand Up @@ -216,7 +216,7 @@ def send(self) -> DjangoProjectBaseNotification:
return notification

if not self.send_at:
notification = self.make_send(notification, self._extra_data)
SendNotificationService(settings=settings).make_send(notification, self._extra_data, resend=False)
else:
if not self.persist:
raise Exception("Delayed notification must be persisted")
Expand Down Expand Up @@ -245,14 +245,17 @@ def send(self) -> DjangoProjectBaseNotification:
return notification

def _ensure_channels(
self, channels: List[str], notification: DjangoProjectBaseNotification
self,
channels: List[str],
notification: DjangoProjectBaseNotification,
settings: Optional[Settings] = None,
) -> DjangoProjectBaseNotification:
from django_project_base.notifications.base.channels.mail_channel import MailChannel

extra_data = self._extra_data.get("a_extra_data") or self._extra_data
for channel_name in channels:
# ensure dlr user and check providers
channel = ChannelIdentifier.channel(channel_name, extra_data=extra_data, project_slug=self._project)
channel = ChannelIdentifier.channel(channel_name, settings=settings, project_slug=self._project)

if not channel and extra_data.get("is_system_notification"):
continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,35 @@
from django.core.cache import cache
from django.utils import timezone

from django.conf import Settings
from django_project_base.constants import NOTIFICATION_QUEUE_NAME
from django_project_base.notifications.base.enums import ChannelIdentifier
from django_project_base.notifications.models import DjangoProjectBaseNotification


class SendNotificationMixin(object):
class SendNotificationService(object):
settings: Settings

def __init__(self, settings: Settings) -> None:
super().__init__()
self.settings = settings

def make_send(
self, notification: DjangoProjectBaseNotification, extra_data, resend=False
) -> DjangoProjectBaseNotification:
# TODO: THIS SHOULD BE CALLED ONLY FROM CELERY BACKGROUND TASK

sent_channels: list = []
failed_channels: list = []
dj_settings = getattr(self, "settings", None)

exceptions = ""
from django_project_base.licensing.logic import LogAccessService

if notification.required_channels is None:
return notification
if (
dj_settings
and (phn_allowed := getattr(dj_settings, "IS_PHONE_NUMBER_ALLOWED_FUNCTION", ""))
self.settings
and (phn_allowed := getattr(self.settings, "IS_PHONE_NUMBER_ALLOWED_FUNCTION", ""))
and phn_allowed
):
cache.set("IS_PHONE_NUMBER_ALLOWED_FUNCTION".lower(), phn_allowed, timeout=None)
Expand Down Expand Up @@ -54,8 +62,12 @@ def make_send(
required_channels.add(SmsChannel.name)

for channel_identifier in required_channels:
print(self.settings)
channel = ChannelIdentifier.channel(
channel_identifier, settings=dj_settings, project_slug=notification.project_slug, ensure_dlr_user=False
channel_identifier,
settings=self.settings,
project_slug=notification.project_slug,
ensure_dlr_user=False,
)
try:
# check license
Expand Down Expand Up @@ -130,7 +142,5 @@ def make_send(
],
using=NOTIFICATION_QUEUE_NAME,
)

if dj_settings:
db.connections.close_all()
db.connections.close_all()
return notification
Loading

0 comments on commit 352eda4

Please sign in to comment.