Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notification grouping code #351

Merged
merged 8 commits into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 3 additions & 17 deletions zubhub_backend/zubhub/creators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from creators.tasks import upload_file_task, send_mass_email, send_mass_text, send_whatsapp
from creators.models import Setting
from notifications.models import Notification
from notifications.utils import push_notification
from notifications.utils import push_notification, get_notification_template_name
from creators.models import Creator
from django.template.loader import render_to_string

Expand Down Expand Up @@ -257,24 +257,14 @@ def is_valid_setting(setting: int, notification_type: Notification.Type) -> bool
return setting in enabled_notification_settings[notification_type]


html_based_contacts = {Setting.WEB}
def get_notification_template_name(
contact_method: int, notification_type: Notification.Type) -> str:
file_extension = '.html' if contact_method in html_based_contacts else '.txt'
if contact_method == Setting.EMAIL:
file_extension = ''
return (f'notifications/{notification_type.name.lower()}'
f'/{Setting.CONTACT_CHOICES[cast(int, contact_method) - 1][1].lower()}{file_extension}')


def send_notification(users: List[Creator], source: Creator, contexts,
notification_type: Notification.Type, link: str) -> None:
email_contexts = []
sms_contexts = []

for user, context in zip(users, contexts):
user_setting = Setting.objects.get(creator=user)
context.update({'source': user.username})
context.update({'source': source.username})

if user.phone and user_setting.contact == Setting.WHATSAPP and is_valid_setting(Setting.WHATSAPP, notification_type):
context.update({"phone": user.phone})
Expand All @@ -290,11 +280,7 @@ def send_notification(users: List[Creator], source: Creator, contexts,
context.update({"phone": user.phone})
sms_contexts.append(context)

message = render_to_string(
get_notification_template_name(Setting.WEB, notification_type),
context
).strip()
push_notification(user, source, notification_type, message, link)
push_notification(user, source, notification_type, link, context)

if len(email_contexts) > 0:
send_mass_email.delay(template_name=get_notification_template_name(Setting.EMAIL, notification_type), ctxs=email_contexts, full_template=True)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 3.2 on 2022-03-29 02:14

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('notifications', '0007_alter_notification_link'),
]

operations = [
migrations.RemoveField(
model_name='notification',
name='source',
),
migrations.AddField(
model_name='notification',
name='sources',
field=models.ManyToManyField(blank=True, null=True, related_name='notification_source', to=settings.AUTH_USER_MODEL),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 3.2 on 2022-03-29 16:16

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('notifications', '0008_auto_20220329_0214'),
]

operations = [
migrations.AlterField(
model_name='notification',
name='sources',
field=models.ManyToManyField(blank=True, related_name='notification_source', to=settings.AUTH_USER_MODEL),
),
]
3 changes: 1 addition & 2 deletions zubhub_backend/zubhub/notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class Type(models.IntegerChoices):
)
recipient = models.ForeignKey(
Creator, on_delete=models.CASCADE, null=True, related_name="notification_recipient", blank=True)
source = models.ForeignKey(
Creator, on_delete=models.CASCADE, null=True, related_name="notification_source", blank=True)
sources = models.ManyToManyField(Creator, related_name='notification_source', blank=True)
message = models.CharField(max_length=255, blank=True, null=True)
link = models.CharField(max_length=1000, blank=True, null=True)
viewed = models.BooleanField(default=False)
Expand Down
6 changes: 3 additions & 3 deletions zubhub_backend/zubhub/notifications/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

class NotificationSerializer(serializers.ModelSerializer):
recipient = CreatorMinimalSerializer(read_only=True)
source = CreatorMinimalSerializer(read_only=True)
sources = CreatorMinimalSerializer(read_only=True, many=True)

class Meta:
model = Notification
fields = ('id', 'recipient', 'source', 'date', 'viewed', 'type', 'link', 'message')
fields = ('id', 'recipient', 'sources', 'date', 'viewed', 'type', 'link', 'message')

read_only_field = [
'id', 'recipient', 'source', 'date', 'viewed', 'type', 'link', 'message'
'id', 'recipient', 'sources', 'date', 'viewed', 'type', 'link', 'message'
]
60 changes: 58 additions & 2 deletions zubhub_backend/zubhub/notifications/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,61 @@
from typing import cast
from datetime import datetime, timedelta
from notifications.models import Notification
from creators.models import Setting
from django.template.loader import render_to_string


def push_notification(recipient, source, notification_type, message, link):
return Notification.objects.create(recipient=recipient, source=source, type=notification_type, message=message, link=link)
html_based_contacts = {Setting.WEB}
def get_notification_template_name(
contact_method: int, notification_type: Notification.Type) -> str:
file_extension = '.html' if contact_method in html_based_contacts else '.txt'
if contact_method == Setting.EMAIL:
file_extension = ''
return (f'notifications/{notification_type.name.lower()}'
f'/{Setting.CONTACT_CHOICES[cast(int, contact_method) - 1][1].lower()}{file_extension}')


grouped_notification_types = {Notification.Type.BOOKMARK, Notification.Type.CLAP, Notification.Type.COMMENT, Notification.Type.FOLLOW}
recent_notification_time = timedelta(hours=1)
def push_notification(recipient, source, notification_type, link, context):
template_name = get_notification_template_name(Setting.WEB, notification_type)

check_link = None
if notification_type is not Notification.Type.FOLLOW:
check_link = link

notification = None
if notification_type in grouped_notification_types:
try:
filters = {
'recipient': recipient,
'type': notification_type,
'date__gt': datetime.utcnow() - recent_notification_time
}
if check_link:
filters['link'] = check_link
notification = Notification.objects.filter(**filters).order_by('-date').first()
except Notification.DoesNotExist:
pass

if notification is not None:
notification.sources.add(source)
template_prefix, template_ext = template_name.rsplit('.', 1)
template_name = f'{template_prefix}_many.{template_ext}'
context = {**context, 'sources': notification.sources.all()}
notification.message = render_to_string(
template_name,
context
).strip()
notification.date = datetime.now()
notification.viewed = False
notification.save()
return

message = render_to_string(
template_name,
context
)
notification = Notification.objects.create(recipient=recipient, type=notification_type, message=message, link=link)
notification.sources.set([source])
notification.save()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ sources|length }} tinkerers bookmarked your project.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<strong>{{ sources|length }}</strong> clapped for your project.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<strong>{{ sources|length }}</strong> tinkerers commented on your project.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<strong>{{ sources|length }}</strong> tinkerers started following you.
Original file line number Diff line number Diff line change
Expand Up @@ -98,31 +98,32 @@ const NotificationPanel = ({ open, anchorEl }) => {
);

const getAllNotificationView = () => {
const newNotificationsLength = newNotifications.length;
const earlierNotificationsLength = earlierNotifications.length;
const hasNewNotifications = newNotifications.length > 0;
const hasEarlierNotifications = earlierNotifications.length > 0;

return (
<div
className={classes.notificationsWrapper}
onScroll={handleScroll}
ref={notificationsWrapperRef}
>
{newNotificationsLength > 0 && (
{hasNewNotifications && (
<h2 className={classes.panelSubheadingTextStyle}>New</h2>
)}
{newNotifications.map(notification => (
<p style={{ color: 'black', padding: '50px 0px' }}>
{notification.message}
</p>
))}
{earlierNotificationsLength > 0 && (
{hasEarlierNotifications && (
<h2 className={classes.panelSubheadingTextStyle}>Earlier</h2>
)}
{earlierNotifications.map(notification => (
<p style={{ color: 'black', padding: '50px 0px' }}>
{notification.message}
</p>
))}
{!loading && !hasNewNotifications && !hasEarlierNotifications && <p>You have no notifications in this category.</p>}
{loading && getLoadingSpinner()}
</div>
);
Expand All @@ -139,6 +140,7 @@ const NotificationPanel = ({ open, anchorEl }) => {
{notification.message}
</p>
))}
{!loading && unreadNotifications.length === 0 && <p>You have no notifications in this category.</p>}
{loading && getLoadingSpinner()}
</div>
);
Expand Down