Skip to content

Commit

Permalink
Merge pull request #75 from lissa3/jobs
Browse files Browse the repository at this point in the history
sending news from dj-extentions crohn to management command
  • Loading branch information
lissa3 authored Nov 5, 2023
2 parents c3efad7 + db1ce14 commit 3d7dbf6
Show file tree
Hide file tree
Showing 34 changed files with 242 additions and 248 deletions.
17 changes: 17 additions & 0 deletions reqs/reqlinux.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
#
asgiref==3.6.0
# via django
boto3==1.28.77
# via -r reqs\reqlinux.in
botocore==1.31.78
# via
# boto3
# s3transfer
certifi==2023.5.7
# via
# requests
Expand Down Expand Up @@ -59,6 +65,10 @@ django-widget-tweaks==1.4.12
# via -r reqs\reqlinux.in
idna==3.4
# via requests
jmespath==1.0.1
# via
# boto3
# botocore
oauthlib==3.2.2
# via requests-oauthlib
pillow==9.5.0
Expand All @@ -73,6 +83,8 @@ pycparser==2.21
# via cffi
pyjwt[crypto]==2.7.0
# via django-allauth
python-dateutil==2.8.2
# via botocore
python-magic==0.4.27
# via -r reqs\reqlinux.in
python3-openid==3.2.0
Expand All @@ -86,8 +98,12 @@ requests==2.30.0
# requests-oauthlib
requests-oauthlib==1.3.1
# via django-allauth
s3transfer==0.7.0
# via boto3
sentry-sdk==1.2
# via -r reqs\reqlinux.in
six==1.16.0
# via python-dateutil
sqlparse==0.4.4
# via django
typing-extensions==4.7.1
Expand All @@ -98,5 +114,6 @@ unidecode==1.3.6
# via -r reqs\reqlinux.in
urllib3==2.0.2
# via
# botocore
# requests
# sentry-sdk
23 changes: 11 additions & 12 deletions sandbox/conf/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@
]


LANGUAGE_CODE = "en-us"
LANGUAGE_CODE = "en"
LANGUAGES = (("ru", _("Russian")), ("en", _("English")), ("uk", _("Ukrainian")))

USE_I18N = True
Expand Down Expand Up @@ -167,8 +167,7 @@
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
EMAIL_PORT = env("EMAIL_PORT")
EMAIL_USE_TLS = True
EMAIL_BACKEND = env("EMAIL_BACKEND")
# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" # dev.py
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"


# img upload limits
Expand Down Expand Up @@ -392,14 +391,14 @@

# AWS

AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")
# AWS_ACCESS_KEY_ID = env("AWS_ACCESS_KEY_ID")
# AWS_SECRET_ACCESS_KEY = env("AWS_SECRET_ACCESS_KEY")
# AWS_STORAGE_BUCKET_NAME = env("AWS_STORAGE_BUCKET_NAME")

AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"
# AWS_S3_FILE_OVERWRITE = False
# AWS_DEFAULT_ACL = None
# DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage"

AWS_QUERYSTRING_AUTH = False # key will be not present in url
AWS_S3_MAX_MEMORY_SIZE = 2200000
AWS_S3_REGION_NAME = "eu-central-1"
# AWS_QUERYSTRING_AUTH = False # key will be not present in url
# AWS_S3_MAX_MEMORY_SIZE = 2200000
# AWS_S3_REGION_NAME = "eu-central-1"
2 changes: 1 addition & 1 deletion sandbox/conf/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
"PORT": "5432",
}
}

# use in-memory-db
# let op: email confirmation will be NOT in console
# EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"


USE_CAPCHA = False
1 change: 0 additions & 1 deletion src/comments/tests/test_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ def test_error_submit_no_body_root_commet(self):
div_comms = resp_submit.html.find("div", class_="comms")

msg_txt = _("This field is required.")
print(resp_submit.context["form"].errors)

self.assertEqual(self.resp.status_code, 200)
self.assertEqual(resp_submit.status_code, 200)
Expand Down
1 change: 1 addition & 0 deletions src/contacts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class NewsLetterAdmin(admin.ModelAdmin):
related posts status should be changd
"""

list_display_links = ["title"]
date_hierarchy = "added_at"
search_fields = ("title", "letter_status")

Expand Down
File renamed without changes.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,39 @@

from django.conf import settings
from django.core import mail
from django.core.management.base import BaseCommand
from django.template.loader import render_to_string
from django.utils import timezone
from django_extensions.management.jobs import WeeklyJob

from src.contacts.exceptions import * # noqa
from src.contacts.models import NewsLetter
from src.posts.models.post_model import Post
from src.profiles.models import Profile


class Job(WeeklyJob):
class Command(BaseCommand):
"""
users: active status and profile wanted_niews
will get email with news weekly;
will get email with news weekly?;
News letter may not contain links to posts
TODO: better way to arrange unsubscribe
"""

help = "Send news letter" # noqa
help = "Send a newsletter to subscribed users" # noqa

def execute(self):
def handle(self, *args, **options):
_date = timezone.localdate()
str_date = _date.strftime("%d/%m/%Y")
stamp = f"Newsletter {_date:%A}, {_date:%b}. {_date:%d} {str_date}"
domain = settings.ABSOLUTE_URL_BASE
profiles = Profile.objects.send_news().select_related("user")
letter = NewsLetter.objects.filter(letter_status=1).last()
ctx = {"letter": letter, "domain": domain}

if profiles and letter:
try:
posts = Post.objects.filter(send_status=1, letter=letter)
posts = Post.objects.get_public().filter(send_status=1, letter=letter)
ctx.update({"posts": posts})
for profile in profiles:
ctx.update({"uuid": profile.uuid})
Expand Down Expand Up @@ -63,3 +64,5 @@ def execute(self):
raise NewsFansNotFoundException("No profiles not send news")
elif not letter:
raise LetterNotFoundException("No letter to send")

self.stdout.write(self.style.SUCCESS("Successfully sent newletter"))
92 changes: 49 additions & 43 deletions src/contacts/tests/test_jobs.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import time_machine
from django.conf import settings
from django.core import mail
from django.core.management import call_command
from django.test import TestCase, override_settings
from django.urls import reverse

from src.contacts.exceptions import * # noqa
from src.contacts.jobs.send_news import Job as SendMailJob
from src.contacts.models import NewsLetter
from src.posts.models.post_model import Post
from src.posts.tests.factories import PostFactory
Expand All @@ -12,57 +14,60 @@
from .factories import NewsLetterFactory


class TestSendEmailJob:
@override_settings(LANGUAGE_CODE="ru", LANGUAGES=(("ru", "Russian"),))
class TestSendEmailJob(TestCase):
@time_machine.travel("2023-07-17 00:00 +0000")
def test_send_news_with_posts_links(self, mailoutbox):
def test_send_news_with_posts_links(self):
"""
active user (can) get news letter via email
with corresp links to posts;
if sending OK: letter and related posts
change their status
change their status;
email (html)text contains a link to unsubscribe
"""
subject = "Newsletter Monday, Jul. 17 17/07/2023"
profile = ProfileFactory(want_news=True)
domain = settings.ABSOLUTE_URL_BASE
letter = NewsLetterFactory(letter_status=1)
post = PostFactory(send_status=1, letter=letter, title_ru="заголовок")
post = PostFactory(send_status=1, status=2, letter=letter, title_ru="заголовок")
post_title = post.title_ru

short_url = reverse("contacts:end_news", kwargs={"uuid": profile.uuid})
full_link_unsub = f"{domain}{short_url}"
send_mail_job = SendMailJob()
send_mail_job.execute()
call_command("send_news_letter")

assert len(mailoutbox) == 1
self.assertEqual(len(mail.outbox), 1)

mail = mailoutbox[0]
html_msg = mail.alternatives[0][0]
sent_mail = mail.outbox[0]

assert mail.to == [profile.user.email]
assert mail.subject == subject
html_msg = sent_mail.alternatives[0][0]

assert letter.text in mail.body
assert letter.text in html_msg
# TODO: change title for a link to post
assert post_title in mail.body
assert post_title in html_msg
# email (html)text contains a link to unsubscribe
assert full_link_unsub in mail.body
assert full_link_unsub in html_msg
self.assertTrue(sent_mail.to == [profile.user.email])
self.assertTrue(sent_mail.subject == subject)

self.assertTrue(letter.text in sent_mail.body)
self.assertTrue(letter.text in html_msg)

self.assertIn(post_title, sent_mail.body)
self.assertIn(post_title, html_msg)
self.assertIn(full_link_unsub, sent_mail.body)
self.assertIn(full_link_unsub, html_msg)

# after sending
post_after = Post.objects.filter(send_status=2).last()
letter_after = NewsLetter.objects.filter(letter_status=2).last()

assert post.id == post_after.id
assert post_after.send_status == 2
assert letter.id == letter_after.id
assert letter_after.letter_status == 2
self.assertEqual(post.id, post_after.id)
self.assertEqual(post_after.send_status, 2)
self.assertEqual(letter.id, letter_after.id)
self.assertEqual(letter_after.letter_status, 2)

@time_machine.travel("2023-07-17 00:00 +0000")
def test_send_news_no_posts(self, mailoutbox):
def test_send_news_no_posts(self):
"""
No posts links in the letter no posts with
send_status
email (html)text contains a link to unsubscribe
"""
subject = "Newsletter Monday, Jul. 17 17/07/2023"
profile = ProfileFactory(want_news=True)
Expand All @@ -73,29 +78,30 @@ def test_send_news_no_posts(self, mailoutbox):

short_url = reverse("contacts:end_news", kwargs={"uuid": profile.uuid})
full_link_unsub = f"{domain}{short_url}"
send_mail_job = SendMailJob()
send_mail_job.execute()
call_command("send_news_letter")

self.assertEqual(len(mail.outbox), 1)

assert len(mailoutbox) == 1
sent_mail = mail.outbox[0]
html_msg = sent_mail.alternatives[0][0]
sent_mail = mail.outbox[0]
html_msg = sent_mail.alternatives[0][0]

mail = mailoutbox[0]
html_msg = mail.alternatives[0][0]
self.assertTrue(sent_mail.to == [profile.user.email])
self.assertTrue(sent_mail.subject == subject)

assert mail.to == [profile.user.email]
assert mail.subject == subject
self.assertTrue(letter.text in sent_mail.body)
self.assertTrue(letter.text in html_msg)
self.assertNotIn(post_title, sent_mail.body)
self.assertNotIn(post_title, html_msg)

assert letter.text in mail.body
assert letter.text in html_msg
# TODO: change title for a link to post
assert post_title not in mail.body
assert post_title not in html_msg
# email (html)text contains a link to unsubscribe
assert full_link_unsub in mail.body
assert full_link_unsub in html_msg
self.assertIn(full_link_unsub, sent_mail.body)
self.assertIn(full_link_unsub, html_msg)

# after sending
post_after = Post.objects.filter(send_status=2).count()
letter_after = NewsLetter.objects.filter(letter_status=2).last()

assert post_after == 0
assert letter.id == letter_after.id
assert letter_after.letter_status == 2
self.assertEqual(post_after, 0)
self.assertEqual(letter.id, letter_after.id)
self.assertEqual(letter_after.letter_status, 2)
21 changes: 10 additions & 11 deletions src/contacts/tests/test_mail_fail.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
from unittest import mock

from django.core import mail
from django.core.management import call_command
from django.test import TestCase

from src.accounts.models import User
from src.contacts.jobs.send_news import Job as SendMailJob
from src.profiles.tests.factories.profile_factory import ProfileFactory

from ..exceptions import * # noqa
Expand All @@ -19,9 +19,7 @@ def test_news_not_send(self, mock_fail):
letter = NewsLetterFactory(letter_status=1) # noqa

mock_fail.side_effect = SMTPException

send_mail_job = SendMailJob()
send_mail_job.execute()
call_command("send_news_letter")

self.assertEqual(len(mail.outbox), 0)
self.assertTrue(mock_fail.called)
Expand All @@ -41,9 +39,10 @@ def test_manager_no_news_inactive_user(self):
user.is_active = False
user.save()
letter = NewsLetterFactory(letter_status=1) # noqa
send_mail_job = SendMailJob()

with self.assertRaises(NewsFansNotFoundException) as e:
send_mail_job.execute()
call_command("send_news_letter")

self.assertEqual(str(e.exception), "No profiles not send news")
self.assertEqual(len(mail.outbox), 0)

Expand All @@ -54,9 +53,9 @@ def test_manager_no_news_fans(self):
"""
profile = ProfileFactory() # noqa
letter = NewsLetterFactory(letter_status=1) # noqa
send_mail_job = SendMailJob()

with self.assertRaises(NewsFansNotFoundException) as e:
send_mail_job.execute()
call_command("send_news_letter")

self.assertEqual(str(e.exception), "No profiles not send news")
self.assertEqual(len(mail.outbox), 0)
Expand All @@ -66,9 +65,9 @@ def test_no_letter_no_job(self):
if no letter -> no SendMail
"""
profile = ProfileFactory(want_news=True) # noqa
send_mail_job = SendMailJob()

with self.assertRaises(LetterNotFoundException) as e:
send_mail_job.execute()
call_command("send_news_letter")

self.assertEqual(str(e.exception), "No letter to send")
assert len(mail.outbox) == 0
self.assertEqual(len(mail.outbox), 0)
2 changes: 0 additions & 2 deletions src/core/utils/tree_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ def get_cached_trees(queryset) -> list:
for obj in queryset:
obj._cached_children = []
if obj.depth == queryset[0].depth:
# print("line 45 obj depth == qs[0]")
# print("adding to top node")
add_top_node(obj, top_nodes, path)
else:
while not is_child_of(obj, parent := path[-1]):
Expand Down
Loading

0 comments on commit 3d7dbf6

Please sign in to comment.