Skip to content

Commit

Permalink
For #26 ✨ for news
Browse files Browse the repository at this point in the history
letter ✅
  • Loading branch information
lissa3 committed Jul 29, 2023
1 parent dbfa2ed commit 3672d42
Show file tree
Hide file tree
Showing 13 changed files with 210 additions and 20 deletions.
2 changes: 1 addition & 1 deletion sandbox/conf/dev.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .base import * # noqa

INTERNAL_IPS = ["127.0.0.1"]

ABSOLUTE_URL_BASE = "http://127.0.0.1:8000"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
Expand Down
17 changes: 3 additions & 14 deletions src/accounts/tests/factories/user_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,8 @@
faker = Faker()


# @factory.django.mute_signals(pre_save, post_save)
# class UserFactory(factory.django.DjangoModelFactory):
# username = factory.Sequence(lambda n: f"user-{n}")
# email = factory.LazyAttribute(lambda _: faker.unique.email())
# password = factory.PostGenerationMethodCall("set_password", "12345abc")

# class Meta:
# model = User
# django_get_or_create = ("username", "email")


class UserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: f"user-{n}")
username = factory.Sequence(lambda _: faker.unique.user_name())
email = factory.LazyAttribute(lambda _: faker.unique.email())
password = factory.PostGenerationMethodCall("set_password", "12345abc")

Expand All @@ -30,7 +19,7 @@ class Meta:


class AdminSupUserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: f"user-{n}")
username = factory.Sequence(lambda _: faker.unique.user_name())
email = factory.LazyAttribute(lambda _: faker.unique.email())
password = factory.PostGenerationMethodCall("set_password", "12345abc")
is_staff = True
Expand All @@ -42,7 +31,7 @@ class Meta:


class StaffUserFactory(factory.django.DjangoModelFactory):
username = factory.Sequence(lambda n: f"user-{n}")
username = factory.Sequence(lambda _: faker.unique.user_name())
email = factory.LazyAttribute(lambda _: faker.unique.email())
password = factory.PostGenerationMethodCall("set_password", "12345abc")
is_staff = True
Expand Down
20 changes: 20 additions & 0 deletions src/contacts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.contrib import admin

from .models import NewsLetter


@admin.register(NewsLetter)
class NewsLetterAdmin(admin.ModelAdmin):
"""
after sending letter status as well as
related posts status should be changd
"""

date_hierarchy = "added_at"
search_fields = ("title", "letter_status")

list_display = ["id", "title", "letter_status"]

list_filter = ["added_at", "letter_status"]
save_on_top = True
list_per_page = 15
Empty file added src/contacts/jobs/__init__.py
Empty file.
53 changes: 53 additions & 0 deletions src/contacts/jobs/send_news.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django.conf import settings
from django.core import mail
from django.template.loader import render_to_string
from django.utils import timezone
from django_extensions.management.jobs import WeeklyJob

from src.contacts.models import NewsLetter
from src.posts.models.post_model import Post
from src.profiles.models import Profile


class Job(WeeklyJob):
"""
users: active status and profile wanted_niews
will get email with news weekly;
let op: Job package;
"""

help = "Send news letter" # noqa

def execute(self):
_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}
posts = Post.objects.filter(send_status=1, letter=letter)
if letter.posts:
ctx.update({"posts": letter.posts.all(), "domain": domain})
if letter and profiles:
text_msg = render_to_string("contacts/emails/letter.txt", ctx)
html_msg = render_to_string("contacts/emails/letter.html", ctx)
try:
for profile in profiles:
mail.send_mail(
subject=stamp,
message=text_msg,
html_message=html_msg,
from_email="From MedSandbox",
recipient_list=[profile.user.email],
)
letter.sended_at = timezone.now()
letter.letter_status = 2
letter.save()
for post in posts:
post.send_status = 2
post.save()

except Exception as e:
print(e)
# TODO: add Log
17 changes: 17 additions & 0 deletions src/contacts/migrations/0002_newsletter_sended_at.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.1 on 2023-07-28 18:44

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("contacts", "0001_initial"),
]

operations = [
migrations.AddField(
model_name="newsletter",
name="sended_at",
field=models.DateField(blank=True, null=True),
),
]
1 change: 1 addition & 0 deletions src/contacts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Status(models.IntegerChoices):
letter_status = models.IntegerField(
choices=Status.choices, default=Status.PENDING, blank=True
)
sended_at = models.DateField(null=True, blank=True)

def __str__(self) -> str:
return f"sent news {self.id}"
Empty file added src/contacts/tests/__init__.py
Empty file.
11 changes: 11 additions & 0 deletions src/contacts/tests/factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import factory

from src.contacts.models import NewsLetter


class NewsLetterFactory(factory.django.DjangoModelFactory):
class Meta:
model = NewsLetter

title = factory.Faker("word")
text = factory.Faker("sentence")
59 changes: 59 additions & 0 deletions src/contacts/tests/test_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import time_machine

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
from src.profiles.tests.factories.profile_factory import ProfileFactory

from .factories import NewsLetterFactory


class TestSendEmailJob:
@time_machine.travel("2023-07-17 00:00 +0000")
def test_send_news(self, mailoutbox):
"""
active user (can) get news letter via email
with corresp links to posts;
if sending OK: letter and related posts
change their status
"""
subject = "Newsletter Monday, Jul. 17 17/07/2023"
profile = ProfileFactory(want_news=True)
post = PostFactory(send_status=1)
post_title = post.title

letter = NewsLetterFactory(letter_status=1)
post.letter = letter
post.save()
# TODO: add a tag with link
# domain = settings.ABSOLUTE_URL_BASE
# link = f'<a href="{domain}'

send_mail_job = SendMailJob()
send_mail_job.execute()

assert len(mailoutbox) == 1

mail = mailoutbox[0]

html_msg = mail.alternatives[0][0]

assert mail.to == [profile.user.email]
assert mail.subject == subject

assert letter.text in mail.body
assert letter.text in html_msg
assert post_title in mail.body
assert post_title in html_msg
# TODO: change title for a link to post
# assert link in mail.body
# assert link in html_msg

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
10 changes: 5 additions & 5 deletions src/posts/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext
from modeltranslation.admin import TranslationAdmin
from treebeard.admin import TreeAdmin
from treebeard.forms import movenodeform_factory

from src.contacts.models import NewsLetter
from src.core.utils.admin_help import admin_link
from src.posts.models.categ_model import Category
from src.posts.models.post_model import Post
Expand Down Expand Up @@ -81,9 +81,6 @@ def show_img(self, obj):
"""if top_img show small thumbnail in admin table"""
if obj.top_img:
return format_html("<img src={} width='60' />", obj.top_img_url)
# return format_html("<a href={}>{}</a>", url, func(self, related_obj))
# if obj.top_img:
# return mark_safe(f"<img src=`!r{obj.top_img_url}` width='60' />")

def display_tags(self, obj):
"""if tags make a flat list of them"""
Expand All @@ -98,6 +95,8 @@ def formfield_for_foreignkey(self, db_field, request, **kwargs):
kwargs["queryset"] = get_user_model().objects.filter(
username=request.user.username
)
if db_field.name == "letter":
kwargs["queryset"] = NewsLetter.objects.filter(letter_status=1)
return super().formfield_for_foreignkey(db_field, request, **kwargs)

def get_readonly_fields(self, request, obj=None):
Expand All @@ -106,12 +105,13 @@ def get_readonly_fields(self, request, obj=None):
author field will be current user from request
"""
if obj is not None:
return self.readonly_fields + ("author",)
return self.readonly_fields + ("author", "letter")
return self.readonly_fields

def add_view(self, request, form_url="", extra_context=None):
data = request.GET.copy()
data["author"] = request.user
data["letter"] = NewsLetter.objects.filter(letter_status=1).last()
request.GET = data
return super().add_view(request, form_url="", extra_context=extra_context)

Expand Down
29 changes: 29 additions & 0 deletions src/templates/contacts/emails/letter.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head><style></style></head>
<body>
<div>
<h3>Greetings from MedSandbox</h3>
<p>Here is some fresh content on our site</p>
{% if letter %}
<p>Letter title: {{letter.title}}</p>
<p>Letter text: {{ letter.text|linebreaksbr }}</p>
<p>Here is a link to read a new article:
{% if posts %}
{% for post in posts %}
<a href="#">Post title: {{post.title}}</a>
{% comment %}
<a href="{{domain}}{% url 'posts:post_detail' letter.post.slug %}">Some post</a></p>
{% endcomment %}
{% endfor%}
{% else %}
<p>No posts</p>
{% endif %}
{% endif %}
<p>Best regards,</p>
<p>Admin</p>
<!-- TODO: Link to unsubscribe: placeholder by now -->
</div>
</body>
</html>
11 changes: 11 additions & 0 deletions src/templates/contacts/emails/letter.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{% load i18n %}Greetings from MedSandbox
Here is some fresh content on our site
{% if letter %}
Date {{ letter.added_at|date:"l, M. j, Y" }}
Letter title: {{letter.title}}
Letter text: {{ letter.text|linebreaksbr }}
{% if posts %}{% for post in posts %}
Post title: {{post.title}}{% endfor%}
{% endif %}{% endif %}
{% comment %} TODO: Link to unsubscribe: placeholder by now
{% endcomment %}

0 comments on commit 3672d42

Please sign in to comment.