Skip to content

Commit 7ec6cdd

Browse files
svarlamovlunny
authored andcommitted
Add 'mark all read' option to notifications (#3097)
* Add 'mark all read' option to notifications Signed-off-by: Sasha Varlamov <[email protected]> * Fix exported comment Signed-off-by: Sasha Varlamov <[email protected]> * Format method comments Signed-off-by: Sasha Varlamov <[email protected]> * Fix exported comment Signed-off-by: Sasha Varlamov <[email protected]> Format method comments Signed-off-by: Sasha Varlamov <[email protected]> Tests for reactions (#3083) * Unit tests for reactions * Fix import order Signed-off-by: Lauris Bukšis-Haberkorns <[email protected]> Fix reaction possition when there is attachments (#3099) Refactor notifications swap function * Accept change to drop beforeupdate call * Update purge notifications error message for consistency * Drop unnecessary check for mark all as read button * Remove debugging comment
1 parent 1ed7f18 commit 7ec6cdd

File tree

7 files changed

+78
-4
lines changed

7 files changed

+78
-4
lines changed

models/fixtures/notification.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,25 @@
1919
issue_id: 2
2020
created_unix: 946684800
2121
updated_unix: 946684800
22+
23+
-
24+
id: 3
25+
user_id: 2
26+
repo_id: 1
27+
status: 3 # pinned
28+
source: 1 # issue
29+
updated_by: 1
30+
issue_id: 2
31+
created_unix: 946684800
32+
updated_unix: 946684800
33+
34+
-
35+
id: 4
36+
user_id: 2
37+
repo_id: 1
38+
status: 1 # unread
39+
source: 1 # issue
40+
updated_by: 1
41+
issue_id: 2
42+
created_unix: 946684800
43+
updated_unix: 946684800

models/notification.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,13 @@ func getNotificationByID(notificationID int64) (*Notification, error) {
311311

312312
return notification, nil
313313
}
314+
315+
// UpdateNotificationStatuses updates the statuses of all of a user's notifications that are of the currentStatus type to the desiredStatus
316+
func UpdateNotificationStatuses(user *User, currentStatus NotificationStatus, desiredStatus NotificationStatus) error {
317+
n := &Notification{Status: desiredStatus, UpdatedBy: user.ID}
318+
_, err := x.
319+
Where("user_id = ? AND status = ?", user.ID, currentStatus).
320+
Cols("status", "updated_by", "updated_unix").
321+
Update(n)
322+
return err
323+
}

models/notification_test.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ func TestNotificationsForUser(t *testing.T) {
3131
statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread}
3232
notfs, err := NotificationsForUser(user, statuses, 1, 10)
3333
assert.NoError(t, err)
34-
if assert.Len(t, notfs, 1) {
34+
if assert.Len(t, notfs, 2) {
3535
assert.EqualValues(t, 2, notfs[0].ID)
3636
assert.EqualValues(t, user.ID, notfs[0].UserID)
37+
assert.EqualValues(t, 4, notfs[1].ID)
38+
assert.EqualValues(t, user.ID, notfs[1].UserID)
3739
}
3840
}
3941

@@ -57,12 +59,12 @@ func TestNotification_GetIssue(t *testing.T) {
5759

5860
func TestGetNotificationCount(t *testing.T) {
5961
assert.NoError(t, PrepareTestDatabase())
60-
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
61-
cnt, err := GetNotificationCount(user, NotificationStatusUnread)
62+
user := AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
63+
cnt, err := GetNotificationCount(user, NotificationStatusRead)
6264
assert.NoError(t, err)
6365
assert.EqualValues(t, 0, cnt)
6466

65-
cnt, err = GetNotificationCount(user, NotificationStatusRead)
67+
cnt, err = GetNotificationCount(user, NotificationStatusUnread)
6668
assert.NoError(t, err)
6769
assert.EqualValues(t, 1, cnt)
6870
}
@@ -79,3 +81,21 @@ func TestSetNotificationStatus(t *testing.T) {
7981
assert.Error(t, SetNotificationStatus(1, user, NotificationStatusRead))
8082
assert.Error(t, SetNotificationStatus(NonexistentID, user, NotificationStatusRead))
8183
}
84+
85+
func TestUpdateNotificationStatuses(t *testing.T) {
86+
assert.NoError(t, PrepareTestDatabase())
87+
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
88+
notfUnread := AssertExistsAndLoadBean(t,
89+
&Notification{UserID: user.ID, Status: NotificationStatusUnread}).(*Notification)
90+
notfRead := AssertExistsAndLoadBean(t,
91+
&Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification)
92+
notfPinned := AssertExistsAndLoadBean(t,
93+
&Notification{UserID: user.ID, Status: NotificationStatusPinned}).(*Notification)
94+
assert.NoError(t, UpdateNotificationStatuses(user, NotificationStatusUnread, NotificationStatusRead))
95+
AssertExistsAndLoadBean(t,
96+
&Notification{ID: notfUnread.ID, Status: NotificationStatusRead})
97+
AssertExistsAndLoadBean(t,
98+
&Notification{ID: notfRead.ID, Status: NotificationStatusRead})
99+
AssertExistsAndLoadBean(t,
100+
&Notification{ID: notfPinned.ID, Status: NotificationStatusPinned})
101+
}

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,7 @@ no_read = You do not have any read notifications.
15471547
pin = Pin notification
15481548
mark_as_read = Mark as read
15491549
mark_as_unread = Mark as unread
1550+
mark_all_as_read = Mark all as read
15501551

15511552
[gpg]
15521553
error.extract_sign = Failed to extract signature

routers/routes/routes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ func RegisterRoutes(m *macaron.Macaron) {
706706
m.Group("/notifications", func() {
707707
m.Get("", user.Notifications)
708708
m.Post("/status", user.NotificationStatusPost)
709+
m.Post("/purge", user.NotificationPurgePost)
709710
}, reqSignIn)
710711

711712
m.Group("/api", func() {

routers/user/notification.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,15 @@ func NotificationStatusPost(c *context.Context) {
112112
url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
113113
c.Redirect(url, 303)
114114
}
115+
116+
// NotificationPurgePost is a route for 'purging' the list of notifications - marking all unread as read
117+
func NotificationPurgePost(c *context.Context) {
118+
err := models.UpdateNotificationStatuses(c.User, models.NotificationStatusUnread, models.NotificationStatusRead)
119+
if err != nil {
120+
c.Handle(500, "ErrUpdateNotificationStatuses", err)
121+
return
122+
}
123+
124+
url := fmt.Sprintf("%s/notifications", setting.AppSubURL)
125+
c.Redirect(url, 303)
126+
}

templates/user/notification/notification.tmpl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@
1414
<a href="{{AppSubUrl}}/notifications?q=read" class="{{if eq .Status 2}}active{{end}} item">
1515
{{.i18n.Tr "notification.read"}}
1616
</a>
17+
{{if and (eq .Status 1) (.NotificationUnreadCount)}}
18+
<form action="{{AppSubUrl}}/notifications/purge" method="POST" style="margin-left: auto;">
19+
{{$.CsrfTokenHtml}}
20+
<button class="ui mini button primary" title='{{$.i18n.Tr "notification.mark_all_as_read"}}'>
21+
<i class="octicon octicon-checklist"></i>
22+
</button>
23+
</form>
24+
{{end}}
1725
</div>
1826
<div class="ui bottom attached active tab segment">
1927
{{if eq (len .Notifications) 0}}

0 commit comments

Comments
 (0)