From adf091fa07e92fe193f9782cea57a4dda98a4466 Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:34:32 +0530 Subject: [PATCH] fix: email notifications (#3457) * fix: email-template design * fix: priority and state new value * dev: update template with comments, cta text and view issue button. * dev: fix priority and state * dev: update data condition * fix: added avatar url * fix: comment avatar url * fix: priority, labels, state design * style: assignee property * dev: fix template for comments and profile changes * fix: spacing between properties * fix: todo image for state change * fix: blocking and blocked by value change * dev: update template summsary * fix: blocking, duplicate * fix: comments spacing * chore: improve `state change` checkbox logic. * fix: email notification message change * fix: updated date format * fix: updates text color * fix: labels sequence rendering * fix: schedular time change --------- Co-authored-by: LAKHAN BAHETI Co-authored-by: pablohashescobar Co-authored-by: Prateek Shourya --- .../plane/bgtasks/email_notification_task.py | 45 +- apiserver/plane/bgtasks/notification_task.py | 6 +- apiserver/plane/celery.py | 2 +- .../emails/notifications/issue-updates.html | 1749 +++++++++-------- .../preferences/email-notification-form.tsx | 2 +- 5 files changed, 938 insertions(+), 866 deletions(-) diff --git a/apiserver/plane/bgtasks/email_notification_task.py b/apiserver/plane/bgtasks/email_notification_task.py index 86b6d938e..cf7255585 100644 --- a/apiserver/plane/bgtasks/email_notification_task.py +++ b/apiserver/plane/bgtasks/email_notification_task.py @@ -164,30 +164,25 @@ def send_email_notification( } ) activity_time = changes.pop("activity_time") - template_data.append( - { - "actor_detail": { - "avatar_url": actor.avatar, - "first_name": actor.first_name, - "last_name": actor.last_name, - }, - "changes": changes, - "issue_details": { - "name": issue.name, - "identifier": f"{issue.project.identifier}-{issue.sequence_id}", - }, - "activity_time": str(activity_time), - } - ) + # Parse the input string into a datetime object + formatted_time = datetime.strptime(activity_time, "%Y-%m-%d %H:%M:%S").strftime("%H:%M %p") - span = f"""""" + if changes: + template_data.append( + { + "actor_detail": { + "avatar_url": actor.avatar, + "first_name": actor.first_name, + "last_name": actor.last_name, + }, + "changes": changes, + "issue_details": { + "name": issue.name, + "identifier": f"{issue.project.identifier}-{issue.sequence_id}", + }, + "activity_time": str(formatted_time), + } + ) summary = "updates were made to the issue by" @@ -204,11 +199,10 @@ def send_email_notification( "receiver": { "email": receiver.email, }, - "issue_unsubscribe": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}", + "issue_url": f"{base_api}/{str(issue.project.workspace.slug)}/projects/{str(issue.project.id)}/issues/{str(issue.id)}", "user_preference": f"{base_api}/profile/preferences/email", "comments": comments, } - print(json.dumps(context)) html_content = render_to_string( "emails/notifications/issue-updates.html", context ) @@ -236,7 +230,6 @@ def send_email_notification( EmailNotificationLog.objects.filter( pk__in=email_notification_ids ).update(sent_at=timezone.now()) - print("Email Sent") return except Exception as e: print(e) diff --git a/apiserver/plane/bgtasks/notification_task.py b/apiserver/plane/bgtasks/notification_task.py index bcd0f8543..6cfbec72a 100644 --- a/apiserver/plane/bgtasks/notification_task.py +++ b/apiserver/plane/bgtasks/notification_task.py @@ -334,7 +334,11 @@ def notifications( user_id=subscriber ) - for issue_activity in issue_activities_created: + for issue_activity in issue_activities_created: + # If activity done in blocking then blocked by email should not go + if issue_activity.get("issue_detail").get("id") != issue_id: + continue; + # Do not send notification for description update if issue_activity.get("field") == "description": continue diff --git a/apiserver/plane/celery.py b/apiserver/plane/celery.py index 11a88de57..0912e276a 100644 --- a/apiserver/plane/celery.py +++ b/apiserver/plane/celery.py @@ -31,7 +31,7 @@ app.conf.beat_schedule = { }, "check-every-five-minutes-to-send-email-notifications": { "task": "plane.bgtasks.email_notification_task.stack_email_notification", - "schedule": crontab(minute='*/1') + "schedule": crontab(minute='*/5') }, } diff --git a/apiserver/templates/emails/notifications/issue-updates.html b/apiserver/templates/emails/notifications/issue-updates.html index 2bf5b69ec..4374846df 100644 --- a/apiserver/templates/emails/notifications/issue-updates.html +++ b/apiserver/templates/emails/notifications/issue-updates.html @@ -6,10 +6,8 @@ > - - - Updates on Issue + Updates on issue - - - - - - - - - -
- +
+
+ + + +
+
+ +
+
+ + +
+
+
-
- - - - Plane - -
+

+ {{ issue.issue_identifier }} updates +

+

+ {{ issue.name }}: {{ issue.issue_identifier }} +

-
- - - - + + +
-
+
+ +

+ {% if data.1 %}{{ data|length }}{% endif %} {{ summary }} + + {{ data.0.actor_detail.first_name}} + {{data.0.actor_detail.last_name }} + +

+ {% if comments.0 %} +

+ {{ comments|length }} {% if comments|length == 1 %}comment was{% else %}comments were{% endif %} left by + + {% if comments|length == 1 %} + {{ data.0.actor_detail.first_name }} + {{ data.0.actor_detail.last_name }} + {% else %} + {{ data.0.actor_detail.first_name }} + {{ data.0.actor_detail.last_name }} and others + {% endif %} + +

+ {% endif %} + {% if mentions and comments.0 and data.0 %} +

+ There are 3 new updates, added 1 new comment and, you were + + @{{ data.0.actor_detail.first_name}} + {{data.0.actor_detail.last_name }} + + mentioned a comment of this issue. +

+ {% endif %} + {% for update in data %} {% if update.changes.name %} + +

+ The issue title has been updated from “{{update.changes.user.old_value.0}}“ to "{{update.changes.user.new_value|last}}" +

+ {% endif %} + + {% if data %} +
+ +
+

+ Updates +

+
+ +
+ + + + + + + +
+ {% if update.actor_detail.avatar_url %} + + {% else %} + + + + +
+ + {{ update.actor_detail.first_name.0 }} + +
+ {% endif %} +
+

+ {{ update.actor_detail.first_name }} {{ update.actor_detail.last_name }} +

+
+

+ {{ update.activity_time }} +

+
+ {% if update.changes.target_date %} + + + + + + + +
+ + +
+

+ Due Date: +

+
+
+

+ {{ update.changes.target_date.new_value.0 }} +

+
+ {% endif %} {% if update.changes.duplicate %} + + + + + + + + +
+ + + Duplicate: + + + {% for duplicate in update.changes.duplicate.new_value %} + + {{ duplicate }} + + {% endfor %} +
+ {% endif %} + + {% if update.changes.assignees %} + + + + + {% if update.changes.assignees.new_value.0 %} + + {% endif %} {% if update.changes.assignees.new_value.1 %} + + {% endif %} {% if update.changes.assignees.old_value.0 %} + + {% endif %} {% if update.changes.assignees.old_value.1 %} + + {% endif %} + +
+ + +

+ Assignees: +

+
+

+ {{ update.changes.assignees.new_value.0 }} +

+
+

+ +{{ update.changes.assignees.new_value|length|add:"-1"}} + more +

+
+

+ {{update.changes.assignees.old_value.0}} +

+
+

+ +{{ update.changes.assignees.old_value|length|add:"-1"}} + more +

+
+ {% endif %} {% if update.changes.labels %} + + + + + + {% if update.changes.labels.new_value.0 %} + + {% endif %} + {% if update.changes.labels.new_value.1 %} + + {% endif %} + {% if update.changes.labels.old_value.0 %} + + {% endif %} + {% if update.changes.labels.old_value.1 %} + + {% endif %} + +
+ + +

+ Labels: +

+
+

+ {{update.changes.labels.new_value.0}} +

+
+

+ +{{ update.changes.labels.new_value|length|add:"-1"}} more +

+
+

+ {{update.changes.labels.old_value.0}} +

+
+

+ +{{ update.changes.labels.old_value|length|add:"-1"}} more +

+
+ {% endif %} + + {% if update.changes.state %} + + + + + + + + + + +
+ + +

+ State: +

+
+ + +

+ {{ update.changes.state.old_value.0 }} +

+
+ + + + +

+ {{update.changes.state.new_value|last }} +

+
+ {% endif %} {% if update.changes.link %} + + + + + + + +
+ + +

+ Links: +

+
+ {% for link in update.changes.link.new_value %} + + {{ link }} + + {% endfor %} + {% if update.changes.link.old_value|length > 0 %} + {% if update.changes.link.old_value.0 != "None" %} +

+ 2 Links were removed +

+ {% endif %} + {% endif %} +
+ {% endif %} + {% if update.changes.priority %} + + + + + + + + + + +
+ + +

+ Priority: +

+
+

+ {{ update.changes.priority.old_value.0 }} +

+
+ + +

+ {{ update.changes.priority.new_value|last }} +

+
+ {% endif %} + {% if update.changes.blocking.new_value %} + + + + + + + + +
+ + + Blocking: + + + {% for blocking in update.changes.blocking.new_value %} + + {{blocking}} + + {% endfor %} +
+ {% endif %} +
+
+ {% endif %} + + {% endfor %} {% if comments.0 %} + +
+ +

+ Comments +

+ + {% for comment in comments %} + + + + - -
+ {% if comment.actor_detail.avatar_url %} + + {% else %} + + + + +
+ + {{ comment.actor_detail.first_name.0 }} + +
+ {% endif %} +
- -
-

- {{ issue.identifier }} updates -

- {{ issue.name }} -

-
-
-

- {{ summary }} - - {{ data.0.actor_detail.first_name}} {{data.0.actor_detail.last_name }} - -

- - - - - - - {% for update in data %} + {% for actor_comment in comment.actor_comments.new_value %} {% endfor %}
-

- Updates + {{ comment.actor_detail.first_name }} {{ comment.actor_detail.last_name }}

- - - - - - - {% if update.changes.assignees %} - - - - {% endif %} - - {% if update.changes.target_date %} - - - - {% endif %} --> - - {% if update.changes.duplicate %} - - - - {% endif %} - - {% if update.changes.labels %} - - - - {% endif %} - - {% if update.changes.state %} - - - - - - - {% endif %} - - {% if update.changes.link %} - - - - {% endif %} - - {% if update.changes.priority %} - - - - {% endif %} - - {% if update.changes.blocking %} - - - - {% endif %} -
- - - - - - -
- - -

- {{ update.actor_detail.first_name }} {{ update.actor_detail.last_name }} -

-
-

- {{ update.activity_time }} -

-
-
- - - - - {% for assignee in update.changes.assignees.old_value %} - - {% endfor %} - {% if update.changes.assignees.old_value and update.changes.assignee.new_value %} - - {% endif %} - {% for assignee in update.changes.assignees.new_value %} - - {% endfor %} - -
-

- Assignee: -

-
-

- {{ assignee }} -

-
- - -

- {{ assginee }} -

-
-
- - - - - - -
- - -

- Due Date: -

-
-

- {{ update.changes.target_date.new_value.0 }} -

-
-
- - - - - {% for dup in update.changes.duplicate.new_value %} - - {% endfor %} - -
- - -

- Duplicate: -

-
-

- {{ dup }} -

-
-
- - - - - - - -
- - -

- Labels: -

-
- - - {% for label in update.changes.labels.new_value %} - - {% endfor %} - -
-

- {{ label }} -

-
-
-
-
- - - - - - - - - -
- - -

- State: -

-
-

- {{ update.changes.state.old_value.0 }} -

-
-> -

- {{ update.changes.state.new_value.0 }} -

-
-
- - - - - - -
- - -

- Link: -

-
- - {{ update.changes.link.new_value.0 }} - -
-
- - - - - - - - -
- - -

- Priority: -

-
-

- {{ update.changes.priority.old_value.0 }} -

-
- -> - -

- {{ update.changes.priority.new_value.0 }} -

-
-
- - - - - {% for bl in update.changes.blocking.new_value %} - - {% endfor %} - -
- - -

- Blocking: -

-
- - {{ bl }} - -
-
+

+ {{ actor_comment|safe }} +

+
- - {% if comments %} - - - - - - - - - - - - - -
-

- Comments -

-
-
-
- - - - {% for comment in comments %} - - {% endfor %} - -
-
- S -
- -
- - - - - {% for actor_comment in comment.actor_comments %} - - - - {% endfor %} -
-

- {{ comment.actor_detail.first_name }} {{ comment.actor_detail.last_name }} -

-
-
- {{ actor_comment.new_value.0 }} -
-
-
-
- {% endif %} - - -
-
+ {% endfor %} + + {% endif %} + + +
+ View issue +
+
+ -
- - - - -
-
- This email was sent to - {{ receiver.email }}. - If you'd rather not receive this kind of email, - you can unsubscribe to the issue - or - manage your email preferences. - - -
-
-
- - - + + + + +
+
+ This email was sent to + {{ receiver.email }}. + If you'd rather not receive this kind of email, + you can unsubscribe to the issue + or + manage your email preferences. + + +
+
+ diff --git a/web/components/profile/preferences/email-notification-form.tsx b/web/components/profile/preferences/email-notification-form.tsx index ee019e1dd..898044c60 100644 --- a/web/components/profile/preferences/email-notification-form.tsx +++ b/web/components/profile/preferences/email-notification-form.tsx @@ -104,7 +104,7 @@ export const EmailNotificationForm: FC = (props) => type="checkbox" checked={value} onChange={() => { - if (!value) setValue("issue_completed", true); + setValue("issue_completed", !value); onChange(!value); }} className="w-3.5 h-3.5 mx-2 cursor-pointer"