Skip to content

Commit

Permalink
For #26 add via main branch
Browse files Browse the repository at this point in the history
  • Loading branch information
lissa3 committed Nov 8, 2023
1 parent c3efad7 commit 086fb21
Show file tree
Hide file tree
Showing 12 changed files with 152 additions and 109 deletions.
19 changes: 18 additions & 1 deletion 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
# 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" # dev.py


# 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"
Empty file removed src/contacts/jobs/__init__.py
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 All @@ -53,6 +54,7 @@ def execute(self):
for post in posts:
post.send_status = 2
post.save()
self.stdout.write(self.style.SUCCESS("Successfully sent newletter"))

except SMTPException as e:
print("smth went wrong ", e)
Expand Down
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: 1 addition & 1 deletion src/posts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class PostAdmin(TranslationAdmin):
list_display_links = ["title"]
radio_fields = {"status": admin.HORIZONTAL}
save_on_top = True
list_filter = ["status", "created_at", SoftDelFilter]
list_filter = ["status", "created_at", SoftDelFilter, "send_status"]
# list_filter = ["status", "created_at", "is_deleted"]
list_per_page = 15
actions = ("make_posts_published", "set_to_draft", "set_to_review")
Expand Down
Loading

0 comments on commit 086fb21

Please sign in to comment.