Skip to content

Commit eab2500

Browse files
authored
Notifications: allow dismiss user's notifications (#11130)
* Notifications: move logic to self link to the model * Notifications: allow dismiss user's notifications * Reuse the template
1 parent e7849c7 commit eab2500

File tree

9 files changed

+86
-78
lines changed

9 files changed

+86
-78
lines changed

readthedocs/api/v3/serializers.py

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -66,50 +66,7 @@ class NotificationLinksSerializer(BaseLinksSerializer):
6666
_self = serializers.SerializerMethodField()
6767

6868
def get__self(self, obj):
69-
content_type_name = obj.attached_to_content_type.name
70-
if content_type_name == "user":
71-
url = "users-notifications-detail"
72-
path = reverse(
73-
url,
74-
kwargs={
75-
"notification_pk": obj.pk,
76-
"parent_lookup_user__username": obj.attached_to.username,
77-
},
78-
)
79-
80-
elif content_type_name == "build":
81-
url = "projects-builds-notifications-detail"
82-
project_slug = obj.attached_to.project.slug
83-
path = reverse(
84-
url,
85-
kwargs={
86-
"notification_pk": obj.pk,
87-
"parent_lookup_project__slug": project_slug,
88-
"parent_lookup_build__id": obj.attached_to_id,
89-
},
90-
)
91-
92-
elif content_type_name == "project":
93-
url = "projects-notifications-detail"
94-
project_slug = obj.attached_to.slug
95-
path = reverse(
96-
url,
97-
kwargs={
98-
"notification_pk": obj.pk,
99-
"parent_lookup_project__slug": project_slug,
100-
},
101-
)
102-
103-
elif content_type_name == "organization":
104-
url = "organizations-notifications-detail"
105-
path = reverse(
106-
url,
107-
kwargs={
108-
"notification_pk": obj.pk,
109-
"parent_lookup_organization__slug": obj.attached_to.slug,
110-
},
111-
)
112-
69+
path = obj.get_absolute_url()
11370
return self._absolute_url(path)
11471

11572

readthedocs/core/static-src/core/js/site.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
/* Site-specific javascript */
22

3-
// Notifications that can both dismiss and point to a separate URL
3+
// Dismiss a notification
44
module.exports.handle_notification_dismiss = function () {
55
$(document).ready(function () {
66
$('ul.notifications li.notification > a').click(function (ev) {
77
var url = $(this).attr('href');
88
var dismiss_url = $(this).parent().attr('data-dismiss-url');
9+
var csrf_token = $(this).parent().attr('data-csrf-token');
910
if (dismiss_url) {
1011
ev.preventDefault();
11-
$.get(dismiss_url, function (data, text_status, xhr) {
12-
window.location.href = url;
12+
$.ajax({
13+
type: "PATCH",
14+
url: dismiss_url,
15+
data: {
16+
state: "dismissed",
17+
},
18+
headers: {
19+
"X-CSRFToken": csrf_token,
20+
},
21+
}).then((data) => {
22+
$(this).parent().hide();
1323
});
1424
}
1525
else {
16-
$(this).hide();
26+
$(this).parent().hide();
1727
}
1828
});
1929
});

readthedocs/core/static/core/js/site.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readthedocs/notifications/models.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from django.contrib.contenttypes.fields import GenericForeignKey
55
from django.contrib.contenttypes.models import ContentType
66
from django.db import models
7+
from django.urls import reverse
78
from django.utils.translation import gettext_noop as _
89
from django_extensions.db.models import TimeStampedModel
910

@@ -95,3 +96,49 @@ def get_message(self):
9596
)
9697

9798
return message
99+
100+
def get_absolute_url(self):
101+
content_type_name = self.attached_to_content_type.name
102+
if content_type_name == "user":
103+
url = "users-notifications-detail"
104+
path = reverse(
105+
url,
106+
kwargs={
107+
"notification_pk": self.pk,
108+
"parent_lookup_user__username": self.attached_to.username,
109+
},
110+
)
111+
112+
elif content_type_name == "build":
113+
url = "projects-builds-notifications-detail"
114+
project_slug = self.attached_to.project.slug
115+
path = reverse(
116+
url,
117+
kwargs={
118+
"notification_pk": self.pk,
119+
"parent_lookup_project__slug": project_slug,
120+
"parent_lookup_build__id": self.attached_to_id,
121+
},
122+
)
123+
124+
elif content_type_name == "project":
125+
url = "projects-notifications-detail"
126+
project_slug = self.attached_to.slug
127+
path = reverse(
128+
url,
129+
kwargs={
130+
"notification_pk": self.pk,
131+
"parent_lookup_project__slug": project_slug,
132+
},
133+
)
134+
135+
elif content_type_name == "organization":
136+
url = "organizations-notifications-detail"
137+
path = reverse(
138+
url,
139+
kwargs={
140+
"notification_pk": self.pk,
141+
"parent_lookup_organization__slug": self.attached_to.slug,
142+
},
143+
)
144+
return path

readthedocs/organizations/templates/organizations/organization_detail.html

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,7 @@
99
{% block organization-bar-details %}active{% endblock %}
1010

1111
{% block content %}
12-
{% if notifications %}
13-
<ul class="notifications">
14-
{% for notification in notifications %}
15-
<li class="notification">
16-
{{ notification.get_message.get_rendered_body|safe }}
17-
</li>
18-
{% endfor %}
19-
</ul>
20-
{% endif %}
12+
{% include "core/notifications.html" with notifications=notifications %}
2113

2214
<div class="col-major organization-major">
2315
<div class="module organization organization-detail">

readthedocs/templates/base.html

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,7 @@
108108
We need to use a CustomUser to have access to "user.notifications"
109109
See https://docs.djangoproject.com/en/4.2/ref/settings/#std-setting-AUTH_USER_MODEL
110110
{% endcomment %}
111-
{% if user_notifications %}
112-
<ul class="notifications">
113-
{% for notification in user_notifications %}
114-
<li class="notification">
115-
{{ notification.get_message.get_rendered_body|safe }}
116-
</li>
117-
{% endfor %}
118-
</ul>
119-
{% endif %}
111+
{% include "core/notifications.html" with notifications=user_notifications %}
120112

121113
<!-- BEGIN notify -->
122114
{% block notify %}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% load i18n %}
2+
3+
{% if notifications %}
4+
<ul class="notifications">
5+
{% for notification in notifications %}
6+
<li class="notification"
7+
{% if notification.dismissable%}
8+
data-dismiss-url="{{ notification.get_absolute_url }}"
9+
data-csrf-token="{{ csrf_token }}"
10+
{% endif %}>
11+
{% if notification.dismissable %}
12+
<a class="notification-action" href="#">
13+
<span class="icon close" aria-label="{% trans 'Close notification' %}"></span>
14+
</a>
15+
{% endif %}
16+
{{ notification.get_message.get_rendered_body|safe }}
17+
</li>
18+
{% endfor %}
19+
</ul>
20+
{% endif %}

readthedocs/templates/core/project_bar_base.html

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ <h1>
2929

3030
<div class="options">
3131

32-
{% comment %}
33-
All projects with "skip=True" needs to be attached a notification using the new system.
34-
This notification will be shown here using the same style we used before.
35-
{% endcomment %}
36-
37-
{% for notification in notifications %}
38-
<p class="build-failure">
39-
{{ notification.get_message.get_rendered_body|safe }}
40-
</p>
41-
{% endfor %}
42-
4332
<ul>
4433
<li class="{{ overview_active }}"><a href="{{ project.get_absolute_url }}">{% trans "Overview" %}</a></li>
4534

readthedocs/templates/projects/project_detail.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
{% endblock %}
1212

1313
{% block content %}
14+
{% include "core/notifications.html" with notifications=notifications %}
1415
{% include "core/project_details.html" %}
1516
{% endblock %}

0 commit comments

Comments
 (0)